diff --git a/docs/USER_GUIDE.adoc b/docs/USER_GUIDE.adoc index 198eeab74..3ac023659 100644 --- a/docs/USER_GUIDE.adoc +++ b/docs/USER_GUIDE.adoc @@ -90,10 +90,10 @@ service to listen to these webhook requests and acts accordingly by triggering a triggering builds on matching branches or pull requests. Go to "Manage Jenkins" / "Configure System" and locate _Bitbucket Endpoints_. For every endpoint where you want webhooks registered automatically, -check "Manage hooks" and select a "Credential" with enough access to add webhooks to repositories. Since the Credential is used at the system level, +check "Manage hooks" and select a "Credential" with enough access to add webhooks to repositories. Since the Credential is used at the system level, it can be a System scoped credential, which will restrict its usage from Pipelines. -For both Bitbucket _Multibranch Pipelines_ and _Organization folders_ there is an "Override hook management" behavior +For both Bitbucket _Multibranch Pipelines_ and _Organization folders_ there is an "Override hook management" behavior to opt out or adjust system-wide settings. image::images/screenshot-4.png[scaledwidth=90%] @@ -152,6 +152,23 @@ image::images/screenshot-11.png[scaledwidth=90%] image::images/screenshot-12.png[scaledwidth=90%] +[id=bitbucket-mirror-support] +== Mirror support + +A mirrored Git repository can be configured for fetching references. + +The mirror is not used in the following cases: + +- If the source branch in a pull request resides in a different repository, the source branch is fetched from the primary repository while the target branch is fetched from the mirror. + +- During initial pull request scanning, the mirror isn't used because of the current design limitations. + +Cloning from the mirror can only be used with native web-hooks since plugin web-hooks don't provide a mirror identifier. + +For branches and tags, the mirror sync event is used. Thus, at cloning time, the mirror is already synchronized. However, in the case of a pull request event, there is no such guarantee. The plugin optimistically assumes that the mirror is synced and the required commit hashes exist in the mirrored repository at cloning time. If the plugin can't find the required hashes, it falls back to the primary repository. + +image::images/screenshot-13.png[scaledwidth=90%] + [id=bitbucket-misc-config] == Miscellaneous configuration diff --git a/docs/images/screenshot-13.png b/docs/images/screenshot-13.png new file mode 100644 index 000000000..a475ccfd0 Binary files /dev/null and b/docs/images/screenshot-13.png differ diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketApiUtils.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketApiUtils.java new file mode 100644 index 000000000..f33cfca52 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketApiUtils.java @@ -0,0 +1,93 @@ +package com.cloudbees.jenkins.plugins.bitbucket; + +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApi; +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApiFactory; +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketAuthenticator; +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRequestException; +import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketCloudEndpoint; +import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketEndpointConfiguration; +import com.cloudbees.plugins.credentials.CredentialsProvider; +import com.cloudbees.plugins.credentials.common.StandardCredentials; +import hudson.Util; +import hudson.model.Item; +import hudson.util.FormFillFailure; +import hudson.util.ListBoxModel; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import jenkins.authentication.tokens.api.AuthenticationTokens; +import jenkins.model.Jenkins; +import jenkins.scm.api.SCMSourceOwner; +import org.apache.commons.lang.StringUtils; + +public class BitbucketApiUtils { + + private static final Logger LOGGER = Logger.getLogger(BitbucketApiUtils.class.getName()); + + public static ListBoxModel getFromBitbucket(SCMSourceOwner context, + String serverUrl, + String credentialsId, + String repoOwner, + String repository, + BitbucketSupplier listBoxModelSupplier) + throws FormFillFailure { + repoOwner = Util.fixEmptyAndTrim(repoOwner); + if (repoOwner == null) { + return new ListBoxModel(); + } + if (context == null && !Jenkins.get().hasPermission(Jenkins.ADMINISTER) || + context != null && !context.hasPermission(Item.EXTENDED_READ)) { + return new ListBoxModel(); // not supposed to be seeing this form + } + if (context != null && !context.hasPermission(CredentialsProvider.USE_ITEM)) { + return new ListBoxModel(); // not permitted to try connecting with these credentials + } + + String serverUrlFallback = BitbucketCloudEndpoint.SERVER_URL; + // if at least one bitbucket server is configured use it instead of bitbucket cloud + if(BitbucketEndpointConfiguration.get().getEndpointItems().size() > 0){ + serverUrlFallback = BitbucketEndpointConfiguration.get().getEndpointItems().get(0).value; + } + + serverUrl = StringUtils.defaultIfBlank(serverUrl, serverUrlFallback); + StandardCredentials credentials = BitbucketCredentials.lookupCredentials( + serverUrl, + context, + credentialsId, + StandardCredentials.class + ); + + BitbucketAuthenticator authenticator = AuthenticationTokens.convert(BitbucketAuthenticator.authenticationContext(serverUrl), credentials); + + try { + BitbucketApi bitbucket = BitbucketApiFactory.newInstance(serverUrl, authenticator, repoOwner, null, repository); + return listBoxModelSupplier.get(bitbucket); + } catch (FormFillFailure | OutOfMemoryError e) { + throw e; + } catch (IOException e) { + if (e instanceof BitbucketRequestException) { + if (((BitbucketRequestException) e).getHttpCode() == 401) { + throw FormFillFailure.error(credentials == null + ? Messages.BitbucketSCMSource_UnauthorizedAnonymous(repoOwner) + : Messages.BitbucketSCMSource_UnauthorizedOwner(repoOwner)).withSelectionCleared(); + } + } else if (e.getCause() instanceof BitbucketRequestException) { + if (((BitbucketRequestException) e.getCause()).getHttpCode() == 401) { + throw FormFillFailure.error(credentials == null + ? Messages.BitbucketSCMSource_UnauthorizedAnonymous(repoOwner) + : Messages.BitbucketSCMSource_UnauthorizedOwner(repoOwner)).withSelectionCleared(); + } + } + LOGGER.log(Level.SEVERE, e.getMessage(), e); + throw FormFillFailure.error(e.getMessage()); + } catch (Throwable e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + throw FormFillFailure.error(e.getMessage()); + } + } + + public interface BitbucketSupplier { + T get(BitbucketApi bitbucketApi) throws IOException, InterruptedException; + } + +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMBuilder.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMBuilder.java index eafab07d0..46c00e610 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMBuilder.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMBuilder.java @@ -23,11 +23,9 @@ */ package com.cloudbees.jenkins.plugins.bitbucket; -import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApi; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketHref; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepository; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryProtocol; -import com.cloudbees.jenkins.plugins.bitbucket.client.BitbucketCloudApiClient; import com.cloudbees.jenkins.plugins.bitbucket.endpoints.AbstractBitbucketEndpoint; import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketEndpointConfiguration; import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketServerEndpoint; @@ -40,12 +38,8 @@ import hudson.Util; import hudson.plugins.git.GitSCM; import hudson.plugins.git.browser.BitbucketWeb; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import jenkins.plugins.git.AbstractGitSCMSource; import jenkins.plugins.git.GitSCMBuilder; -import jenkins.plugins.git.MergeWithGitSCMExtension; import jenkins.scm.api.SCMHead; import jenkins.scm.api.SCMRevision; import jenkins.scm.api.SCMSource; @@ -68,11 +62,16 @@ public class BitbucketGitSCMBuilder extends GitSCMBuilder cloneLinks = Collections.emptyList(); + private List primaryCloneLinks = List.of(); + + /** + * The clone links for mirror repository if it's configured + */ + @NonNull + private List mirrorCloneLinks = List.of(); /** * The {@link BitbucketRepositoryProtocol} that should be used. @@ -96,21 +95,6 @@ public BitbucketGitSCMBuilder(@NonNull BitbucketSCMSource scmSource, @NonNull SC // we provide a dummy repository URL to the super constructor and then fix is afterwards once we have // the clone links super(head, revision, /*dummy value*/scmSource.getServerUrl(), credentialsId); - withoutRefSpecs(); - if (head instanceof PullRequestSCMHead) { - if (scmSource.buildBitbucketClient() instanceof BitbucketCloudApiClient) { - // TODO fix once Bitbucket Cloud has a fix for https://bitbucket.org/site/master/issues/5814 - String branchName = ((PullRequestSCMHead) head).getBranchName(); - withRefSpec("+refs/heads/" + branchName + ":refs/remotes/@{remote}/" + head.getName()); - } else { - String pullId = ((PullRequestSCMHead) head).getId(); - withRefSpec("+refs/pull-requests/" + pullId + "/from:refs/remotes/@{remote}/" + head.getName()); - } - } else if (head instanceof TagSCMHead ){ - withRefSpec("+refs/tags/" + head.getName() + ":refs/tags/" + head.getName()); - } else { - withRefSpec("+refs/heads/" + head.getName() + ":refs/remotes/@{remote}/" + head.getName()); - } this.scmSource = scmSource; AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(scmSource.getServerUrl()); @@ -130,11 +114,19 @@ public BitbucketGitSCMBuilder(@NonNull BitbucketSCMSource scmSource, @NonNull SC /** * Provides the clone links from the {@link BitbucketRepository} to allow inference of ports for different protocols. * - * @param cloneLinks the clone links. + * @param primaryCloneLinks the clone links for primary repository. + * @param mirrorCloneLinks the clone links for mirror repository if it's configured. * @return {@code this} for method chaining. */ - public BitbucketGitSCMBuilder withCloneLinks(List cloneLinks) { - this.cloneLinks = new ArrayList<>(Util.fixNull(cloneLinks)); + public BitbucketGitSCMBuilder withCloneLinks( + @CheckForNull List primaryCloneLinks, + @CheckForNull List mirrorCloneLinks + ) { + if (primaryCloneLinks == null) { + throw new IllegalArgumentException("Primary clone links shouldn't be null"); + } + this.primaryCloneLinks = primaryCloneLinks; + this.mirrorCloneLinks = Util.fixNull(mirrorCloneLinks); return withBitbucketRemote(); } @@ -149,16 +141,6 @@ public BitbucketSCMSource scmSource() { return scmSource; } - /** - * Returns the clone links (possibly empty). - * - * @return the clone links (possibly empty). - */ - @NonNull - public List cloneLinks() { - return Collections.unmodifiableList(cloneLinks); - } - /** * Configures the {@link IdCredentials#getId()} of the {@link Credentials} to use when connecting to the * {@link #remote()} @@ -206,70 +188,130 @@ public BitbucketGitSCMBuilder withCredentials(String credentialsId, BitbucketRep */ @NonNull public BitbucketGitSCMBuilder withBitbucketRemote() { - SCMHead h = head(); - String repoOwner; - String repository; - BitbucketApi bitbucket = scmSource().buildBitbucketClient(); - if (h instanceof PullRequestSCMHead && bitbucket instanceof BitbucketCloudApiClient) { - // TODO fix once Bitbucket Cloud has a fix for https://bitbucket.org/site/master/issues/5814 - repoOwner = ((PullRequestSCMHead) h).getRepoOwner(); - repository = ((PullRequestSCMHead) h).getRepository(); + SCMHead head = head(); + withoutRefSpecs(); + String headName = head.getName(); + if (head instanceof PullRequestSCMHead) { + withPullRequestRemote((PullRequestSCMHead) head, headName); + } else if (head instanceof TagSCMHead) { + withTagRemote(headName); } else { - // head instanceof BranchSCMHead - repoOwner = scmSource.getRepoOwner(); - repository = scmSource.getRepository(); + withBranchRemote(headName); } + return this; + } - String cloneLink = null; - for (BitbucketHref link : cloneLinks()) { - if (protocol.getType().equals(link.getName())) { - cloneLink = link.getHref(); - break; + private void withPullRequestRemote(PullRequestSCMHead head, String headName) { + String scmSourceRepoOwner = scmSource.getRepoOwner(); + String scmSourceRepository = scmSource.getRepository(); + String pullRequestRepoOwner = head.getRepoOwner(); + String pullRequestRepository = head.getRepository(); + boolean prFromTargetRepository = pullRequestRepoOwner.equals(scmSourceRepoOwner) + && pullRequestRepository.equals(scmSourceRepository); + SCMRevision revision = revision(); + ChangeRequestCheckoutStrategy checkoutStrategy = head.getCheckoutStrategy(); + // PullRequestSCMHead should be refactored to add references to target and source commit hashes. + // So revision should not be used here. There is a hack to use revision to get hashes. + boolean cloneFromMirror = prFromTargetRepository + && !mirrorCloneLinks.isEmpty() + && revision instanceof PullRequestSCMRevision; + String targetBranch = head.getTarget().getName(); + String branchName = head.getBranchName(); + if (prFromTargetRepository) { + withRefSpec("+refs/heads/" + branchName + ":refs/remotes/@{remote}/" + branchName); + if (cloneFromMirror) { + PullRequestSCMRevision pullRequestSCMRevision = (PullRequestSCMRevision) revision; + String primaryRemoteName = remoteName().equals("primary") ? "primary-primary" : "primary"; + String cloneLink = getCloneLink(primaryCloneLinks); + List branchWithHashes; + if (checkoutStrategy == ChangeRequestCheckoutStrategy.MERGE) { + branchWithHashes = List.of( + new BranchWithHash(branchName, pullRequestSCMRevision.getPull().getHash()), + new BranchWithHash(targetBranch, pullRequestSCMRevision.getTargetImpl().getHash()) + ); + } else { + branchWithHashes = List.of( + new BranchWithHash(branchName, pullRequestSCMRevision.getPull().getHash()) + ); + } + withExtension(new FallbackToOtherRepositoryGitSCMExtension(cloneLink, primaryRemoteName, branchWithHashes)); + withMirrorRemote(); + } else { + withPrimaryRemote(); + } + } else { + if (scmSource.isCloud()) { + withRefSpec("+refs/heads/" + branchName + ":refs/remotes/@{remote}/" + headName); + String cloneLink = getCloudRepositoryUri(pullRequestRepoOwner, pullRequestRepository); + withRemote(cloneLink); + } else { + String pullId = head.getId(); + withRefSpec("+refs/pull-requests/" + pullId + "/from:refs/remotes/@{remote}/" + headName); + withPrimaryRemote(); } } - withRemote(bitbucket.getRepositoryUri( - protocol, - cloneLink, - repoOwner, - repository)); - AbstractBitbucketEndpoint endpoint = - BitbucketEndpointConfiguration.get().findEndpoint(scmSource.getServerUrl()); - if (endpoint == null) { - endpoint = new BitbucketServerEndpoint(null, scmSource.getServerUrl(), false, null); + if (head.getCheckoutStrategy() == ChangeRequestCheckoutStrategy.MERGE) { + String hash = revision instanceof PullRequestSCMRevision + ? ((PullRequestSCMRevision) revision).getTargetImpl().getHash() + : null; + String refSpec = "+refs/heads/" + targetBranch + ":refs/remotes/@{remote}/" + targetBranch; + if (!prFromTargetRepository && scmSource.isCloud()) { + String upstreamRemoteName = remoteName().equals("upstream") ? "upstream-upstream" : "upstream"; + withAdditionalRemote(upstreamRemoteName, getCloneLink(primaryCloneLinks), refSpec); + withExtension(new MergeWithGitSCMExtension("remotes/" + upstreamRemoteName + "/" + targetBranch, hash)); + } else { + withRefSpec(refSpec); + withExtension(new MergeWithGitSCMExtension("remotes/" + remoteName() + "/" + targetBranch, hash)); + } } - withBrowser(new BitbucketWeb( - endpoint.getRepositoryUrl( - repoOwner, - repository - ))); + } - // now, if we have to build a merge commit, let's ensure we build the merge commit! - SCMRevision r = revision(); - if (h instanceof PullRequestSCMHead) { - PullRequestSCMHead head = (PullRequestSCMHead) h; - if (head.getCheckoutStrategy() == ChangeRequestCheckoutStrategy.MERGE) { - String name = head.getTarget().getName(); - String localName = head.getBranchName().equals(name) ? "upstream-" + name : name; + @NonNull + public String getCloudRepositoryUri(@NonNull String owner, @NonNull String repository) { + switch (protocol) { + case HTTP: + return "https://bitbucket.org/" + owner + "/" + repository + ".git"; + case SSH: + return "ssh://git@bitbucket.org/" + owner + "/" + repository + ".git"; + default: + throw new IllegalArgumentException("Unsupported repository protocol: " + protocol); + } + } - String remoteName = remoteName().equals("upstream") ? "upstream-upstream" : "upstream"; - withAdditionalRemote(remoteName, - bitbucket.getRepositoryUri( - protocol, - cloneLink, - scmSource().getRepoOwner(), - scmSource().getRepository()), - "+refs/heads/" + name + ":refs/remotes/@{remote}/" + localName); - if ((r instanceof PullRequestSCMRevision) - && ((PullRequestSCMRevision) r).getTarget() instanceof AbstractGitSCMSource.SCMRevisionImpl) { - withExtension(new MergeWithGitSCMExtension("remotes/" + remoteName + "/" + localName, - ((AbstractGitSCMSource.SCMRevisionImpl) ((PullRequestSCMRevision) r).getTarget()) - .getHash())); - } else { - withExtension(new MergeWithGitSCMExtension("remotes/" + remoteName + "/" + localName, null)); - } - } + private void withTagRemote(String headName) { + withRefSpec("+refs/tags/" + headName + ":refs/tags/" + headName); + if (mirrorCloneLinks.isEmpty()) { + withPrimaryRemote(); + } else { + withMirrorRemote(); } - return this; + } + + private void withBranchRemote(String headName) { + withRefSpec("+refs/heads/" + headName + ":refs/remotes/@{remote}/" + headName); + if (mirrorCloneLinks.isEmpty()) { + withPrimaryRemote(); + } else { + withMirrorRemote(); + } + } + + private void withPrimaryRemote() { + String cloneLink = getCloneLink(primaryCloneLinks); + withRemote(cloneLink); + } + + private void withMirrorRemote() { + String cloneLink = getCloneLink(mirrorCloneLinks); + withRemote(cloneLink); + } + + private String getCloneLink(List cloneLinks) { + return cloneLinks.stream() + .filter(link -> protocol.getType().equals(link.getName())) + .findAny() + .orElseThrow(() -> new IllegalStateException("Can't find clone link for protocol " + protocol)) + .getHref(); } /** diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator.java index fd531123b..a542fcb83 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator.java @@ -32,6 +32,8 @@ 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.jenkins.plugins.bitbucket.endpoints.BitbucketServerEndpoint; +import com.cloudbees.jenkins.plugins.bitbucket.server.BitbucketServerWebhookImplementation; import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerProject; import com.cloudbees.plugins.credentials.CredentialsNameProvider; import com.cloudbees.plugins.credentials.common.StandardCredentials; @@ -47,6 +49,7 @@ import hudson.model.TaskListener; import hudson.plugins.git.GitSCM; import hudson.security.AccessControlled; +import hudson.util.FormFillFailure; import hudson.util.FormValidation; import hudson.util.ListBoxModel; import java.io.IOException; @@ -98,6 +101,8 @@ import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; +import static com.cloudbees.jenkins.plugins.bitbucket.BitbucketApiUtils.getFromBitbucket; + public class BitbucketSCMNavigator extends SCMNavigator { private static final Logger LOGGER = Logger.getLogger(BitbucketSCMSource.class.getName()); @@ -106,6 +111,8 @@ public class BitbucketSCMNavigator extends SCMNavigator { private String serverUrl; @CheckForNull private String credentialsId; + @CheckForNull + private String mirrorId; @NonNull private final String repoOwner; @CheckForNull @@ -209,6 +216,11 @@ public String getCredentialsId() { return credentialsId; } + @CheckForNull + public String getMirrorId() { + return mirrorId; + } + public String getRepoOwner() { return repoOwner; } @@ -233,6 +245,11 @@ public void setCredentialsId(@CheckForNull String credentialsId) { this.credentialsId = Util.fixEmpty(credentialsId); } + @DataBoundSetter + public void setMirrorId(String mirrorId) { + this.mirrorId = Util.fixEmpty(mirrorId); + } + /** * Sets the behavioural traits that are applied to this navigator and any {@link BitbucketSCMSource} instances it * discovers. The new traits will take effect on the next navigation through any of the @@ -633,12 +650,33 @@ public FormValidation doCheckCredentialsId(@AncestorInPath SCMSourceOwner contex return BitbucketCredentials.checkCredentialsId(context, value, serverUrl); } + @SuppressWarnings("unused") // used By stapler + public static FormValidation doCheckMirrorId(@QueryParameter String value, @QueryParameter String serverUrl) { + if (!value.isEmpty()) { + BitbucketServerWebhookImplementation webhookImplementation = + BitbucketServerEndpoint.findWebhookImplementation(serverUrl); + if (webhookImplementation == BitbucketServerWebhookImplementation.PLUGIN) { + return FormValidation.error("Mirror can only be used with native webhooks"); + } + } + return FormValidation.ok(); + } + @SuppressWarnings("unused") // used By stapler public ListBoxModel doFillCredentialsIdItems(@AncestorInPath SCMSourceOwner context, @QueryParameter String serverUrl) { return BitbucketCredentials.fillCredentialsIdItems(context, serverUrl); } + @SuppressWarnings("unused") // used By stapler + public ListBoxModel doFillMirrorIdItems(@AncestorInPath SCMSourceOwner context, + @QueryParameter String serverUrl, + @QueryParameter String credentialsId, + @QueryParameter String repoOwner) + throws FormFillFailure { + return getFromBitbucket(context, serverUrl, credentialsId, repoOwner, null, MirrorListSupplier.INSTANCE); + } + public List>> getTraitsDescriptorLists() { BitbucketSCMSource.DescriptorImpl sourceDescriptor = Jenkins.get().getDescriptorByType(BitbucketSCMSource.DescriptorImpl.class); @@ -821,7 +859,8 @@ public SCMSource create(@NonNull String projectName) throws IOException, Interru serverUrl, credentialsId, repoOwner, - projectName) + projectName, + mirrorId) .withRequest(request) .build(); } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource.java index 07428ec60..0700f3a1e 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource.java @@ -23,15 +23,17 @@ */ package com.cloudbees.jenkins.plugins.bitbucket; +import com.cloudbees.jenkins.plugins.bitbucket.BitbucketApiUtils.BitbucketSupplier; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApi; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApiFactory; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketAuthenticator; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketBranch; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketCommit; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketHref; +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketMirroredRepository; +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketMirroredRepositoryDescriptor; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketPullRequest; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepository; -import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryProtocol; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryType; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRequestException; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketTeam; @@ -40,9 +42,12 @@ 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.jenkins.plugins.bitbucket.endpoints.BitbucketServerEndpoint; import com.cloudbees.jenkins.plugins.bitbucket.hooks.HasPullRequests; +import com.cloudbees.jenkins.plugins.bitbucket.server.BitbucketServerWebhookImplementation; +import com.cloudbees.jenkins.plugins.bitbucket.server.client.BitbucketServerAPIClient; +import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerRepository; import com.cloudbees.plugins.credentials.CredentialsNameProvider; -import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardCredentials; import com.damnhandy.uri.template.UriTemplate; import com.fasterxml.jackson.databind.util.StdDateFormat; @@ -124,6 +129,8 @@ import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.interceptor.RequirePOST; +import static com.cloudbees.jenkins.plugins.bitbucket.BitbucketApiUtils.getFromBitbucket; + /** * SCM source implementation for Bitbucket. * @@ -155,6 +162,12 @@ public class BitbucketSCMSource extends SCMSource { @CheckForNull private String credentialsId; + /** + * Bitbucket mirror id + */ + @CheckForNull + private String mirrorId; + /** * Repository owner. * Used to build the repository URL. @@ -235,10 +248,15 @@ public class BitbucketSCMSource extends SCMSource { @CheckForNull private transient /*effectively final*/ Map pullRequestContributorCache; /** - * The cache of the clone links. + * The cache of the primary clone links. */ @CheckForNull - private transient List cloneLinks = null; + private transient List primaryCloneLinks = null; + /** + * The cache of the mirror clone links. + */ + @CheckForNull + private transient List mirrorCloneLinks = null; /** * Constructor. @@ -321,6 +339,15 @@ public void setCredentialsId(@CheckForNull String credentialsId) { this.credentialsId = Util.fixEmpty(credentialsId); } + public String getMirrorId() { + return mirrorId; + } + + @DataBoundSetter + public void setMirrorId(String mirrorId) { + this.mirrorId = Util.fixEmpty(mirrorId); + } + @NonNull public String getRepoOwner() { return repoOwner; @@ -509,7 +536,7 @@ public BitbucketRepositoryType getRepositoryType() throws IOException, Interrupt repositoryType = BitbucketRepositoryType.fromString(r.getScm()); Map> links = r.getLinks(); if (links != null && links.containsKey("clone")) { - cloneLinks = links.get("clone"); + primaryCloneLinks = links.get("clone"); } } return repositoryType; @@ -684,26 +711,15 @@ class Skip extends IOException { if (strategies.get(fork).size() > 1) { branchName = "PR-" + pull.getId() + "-" + strategy.name().toLowerCase(Locale.ENGLISH); } - PullRequestSCMHead head; - if (originBitbucket instanceof BitbucketCloudApiClient) { - head = new PullRequestSCMHead( // - branchName, // - pullRepoOwner, // - pullRepository, // - originalBranchName, // - pull, // - originOf(pullRepoOwner, pullRepository), // - strategy); - } else { - head = new PullRequestSCMHead( // - branchName, // - repoOwner, // - repository, // - originalBranchName, // - pull, // - originOf(pullRepoOwner, pullRepository), // - strategy); - } + PullRequestSCMHead head = new PullRequestSCMHead( // + branchName, // + pullRepoOwner, // + pullRepository, // + originalBranchName, // + pull, // + originOf(pullRepoOwner, pullRepository), // + strategy + ); if (request.process(head, // () -> { // use branch instead of commit to postpone closure initialisation @@ -769,10 +785,6 @@ private void retrieveBranches(final BitbucketSCMSourceRequest request) request.listener().getLogger().println("Looking up " + fullName + " for branches"); final BitbucketApi bitbucket = buildBitbucketClient(); - Map> links = bitbucket.getRepository().getLinks(); - if (links != null && links.containsKey("clone")) { - cloneLinks = links.get("clone"); - } int count = 0; for (final BitbucketBranch branch : request.getBranches()) { request.listener().getLogger().println("Checking branch " + branch.getName() + " from " + fullName); @@ -795,10 +807,6 @@ private void retrieveTags(final BitbucketSCMSourceRequest request) throws IOExce request.listener().getLogger().println("Looking up " + fullName + " for tags"); final BitbucketApi bitbucket = buildBitbucketClient(); - Map> links = bitbucket.getRepository().getLinks(); - if (links != null && links.containsKey("clone")) { - cloneLinks = links.get("clone"); - } int count = 0; for (final BitbucketBranch tag : request.getTags()) { request.listener().getLogger().println("Checking tag " + tag.getName() + " from " + fullName); @@ -888,7 +896,7 @@ protected SCMRevision retrieve(SCMHead head, TaskListener listener) throws IOExc return null; } - return new PullRequestSCMRevision<>( + return new PullRequestSCMRevision( h, new BitbucketGitSCMRevision(h.getTarget(), targetRevision), new BitbucketGitSCMRevision(h, sourceRevision) @@ -1016,36 +1024,13 @@ public SCM build(SCMHead head, SCMRevision revision) { } } assert type != null; + initCloneLinks(); - if (cloneLinks == null) { - BitbucketApi bitbucket = buildBitbucketClient(); - try { - BitbucketRepository r = bitbucket.getRepository(); - Map> links = r.getLinks(); - if (links != null && links.containsKey("clone")) { - cloneLinks = links.get("clone"); - } - } catch (IOException | InterruptedException e) { - LOGGER.log(Level.SEVERE, - "Could not determine clone links of " + getRepoOwner() + "/" + getRepository() - + " on " + getServerUrl() + " for " + getOwner() + " falling back to generated links", - e); - cloneLinks = new ArrayList<>(); - cloneLinks.add(new BitbucketHref("ssh", - bitbucket.getRepositoryUri(BitbucketRepositoryProtocol.SSH, null, - getRepoOwner(), getRepository()) - )); - cloneLinks.add(new BitbucketHref("https", - bitbucket.getRepositoryUri(BitbucketRepositoryProtocol.HTTP, null, - getRepoOwner(), getRepository()) - )); - } - } switch (type) { case GIT: default: return new BitbucketGitSCMBuilder(this, head, revision, getCredentialsId()) - .withCloneLinks(cloneLinks) + .withCloneLinks(primaryCloneLinks, mirrorCloneLinks) .withTraits(traits) .build(); @@ -1068,7 +1053,7 @@ public SCMRevision getTrustedRevision(@NonNull SCMRevision revision, @NonNull Ta } catch (WrappedException wrapped) { wrapped.unwrap(); } - PullRequestSCMRevision rev = (PullRequestSCMRevision) revision; + PullRequestSCMRevision rev = (PullRequestSCMRevision) revision; listener.getLogger().format("Loading trusted files from base branch %s at %s rather than %s%n", head.getTarget().getName(), rev.getTarget(), rev.getPull()); return rev.getTarget(); @@ -1107,7 +1092,7 @@ protected List retrieveActions(@CheckForNull SCMSourceEvent event, BitbucketRepository r = bitbucket.getRepository(); Map> links = r.getLinks(); if (links != null && links.containsKey("clone")) { - cloneLinks = links.get("clone"); + primaryCloneLinks = links.get("clone"); } result.add(new BitbucketRepoMetadataAction(r)); String defaultBranch = bitbucket.getDefaultBranch(); @@ -1236,6 +1221,99 @@ public static void setEventDelaySeconds(int eventDelaySeconds) { BitbucketSCMSource.eventDelaySeconds = Math.min(300, Math.max(0, eventDelaySeconds)); } + private void initCloneLinks() { + if (primaryCloneLinks == null) { + BitbucketApi bitbucket = buildBitbucketClient(); + initPrimaryCloneLinks(bitbucket); + if (mirrorId != null && mirrorCloneLinks == null) { + initMirrorCloneLinks((BitbucketServerAPIClient) bitbucket, mirrorId); + } + } + if (mirrorId != null && mirrorCloneLinks == null) { + BitbucketApi bitbucket = buildBitbucketClient(); + initMirrorCloneLinks((BitbucketServerAPIClient) bitbucket, mirrorId); + } + } + + private void initMirrorCloneLinks(BitbucketServerAPIClient bitbucket, String mirrorIdLocal) { + try { + mirrorCloneLinks = getCloneLinksFromMirror(bitbucket, mirrorIdLocal); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "Could not determine mirror clone links of " + getRepoOwner() + "/" + getRepository() + + " on " + getServerUrl() + " for " + getOwner() + " falling back to primary server", + e); + } + } + + private List getCloneLinksFromMirror( + BitbucketServerAPIClient bitbucket, + String mirrorIdLocal + ) throws IOException, InterruptedException { + // Mirrors are supported only by Bitbucket Server + BitbucketServerRepository r = (BitbucketServerRepository) bitbucket.getRepository(); + List mirrors = bitbucket.getMirrors(r.getId()); + BitbucketMirroredRepositoryDescriptor mirroredRepositoryDescriptor = mirrors.stream() + .filter(it -> mirrorIdLocal.equals(it.getMirrorServer().getId())) + .findFirst() + .orElseThrow(() -> + new IllegalStateException("Could not find mirror descriptor for mirror id " + mirrorIdLocal) + ); + if (!mirroredRepositoryDescriptor.getMirrorServer().isEnabled()) { + throw new IllegalStateException("Mirror is disabled for mirror id " + mirrorIdLocal); + } + Map> mirrorDescriptorLinks = mirroredRepositoryDescriptor.getLinks(); + if (mirrorDescriptorLinks == null) { + throw new IllegalStateException("There is no repository descriptor links for mirror id " + mirrorIdLocal); + } + List self = mirrorDescriptorLinks.get("self"); + if (self == null || self.isEmpty()) { + throw new IllegalStateException("There is no self-link for mirror id " + mirrorIdLocal); + } + String selfLink = self.get(0).getHref(); + BitbucketMirroredRepository mirroredRepository = bitbucket.getMirroredRepository(selfLink); + if (!mirroredRepository.isAvailable()) { + throw new IllegalStateException("Mirrored repository is not available for mirror id " + mirrorIdLocal); + } + Map> mirroredRepositoryLinks = mirroredRepository.getLinks(); + if (mirroredRepositoryLinks == null) { + throw new IllegalStateException("There is no mirrored repository links for mirror id " + mirrorIdLocal); + } + List mirroredRepositoryCloneLinks = mirroredRepositoryLinks.get("clone"); + if (mirroredRepositoryCloneLinks == null) { + throw new IllegalStateException("There is no mirrored repository clone links for mirror id " + mirrorIdLocal); + } + return mirroredRepositoryCloneLinks; + } + + private void initPrimaryCloneLinks(BitbucketApi bitbucket) { + try { + primaryCloneLinks = getCloneLinksFromPrimary(bitbucket); + } catch (Exception e) { + throw new IllegalStateException( + "Could not determine clone links of " + getRepoOwner() + "/" + getRepository() + + " on " + getServerUrl() + " for " + getOwner() + " falling back to generated links", + e); + } + } + + private List getCloneLinksFromPrimary(BitbucketApi bitbucket) throws IOException, InterruptedException { + BitbucketRepository r = bitbucket.getRepository(); + Map> links = r.getLinks(); + if (links == null) { + throw new IllegalStateException("There is no links"); + } + List cloneLinksLocal = links.get("clone"); + if (cloneLinksLocal == null) { + throw new IllegalStateException("There is no clone links"); + } + return cloneLinksLocal; + } + + public boolean isCloud() { + return BitbucketCloudEndpoint.SERVER_URL.equals(serverUrl); + } + @Symbol("bitbucket") @Extension public static class DescriptorImpl extends SCMSourceDescriptor { @@ -1265,6 +1343,18 @@ public static FormValidation doCheckServerUrl(@AncestorInPath SCMSourceOwner con return FormValidation.ok(); } + @SuppressWarnings("unused") // used By stapler + public static FormValidation doCheckMirrorId(@QueryParameter String value, @QueryParameter String serverUrl) { + if (!value.isEmpty()) { + BitbucketServerWebhookImplementation webhookImplementation = + BitbucketServerEndpoint.findWebhookImplementation(serverUrl); + if (webhookImplementation == BitbucketServerWebhookImplementation.PLUGIN) { + return FormValidation.error("Mirror can only be used with native webhooks"); + } + } + return FormValidation.ok(); + } + @SuppressWarnings("unused") // used By stapler public boolean isServerUrlSelectable() { return BitbucketEndpointConfiguration.get().isEndpointSelectable(); @@ -1291,40 +1381,11 @@ public ListBoxModel doFillRepositoryItems(@AncestorInPath SCMSourceOwner context @QueryParameter String credentialsId, @QueryParameter String repoOwner) throws IOException, InterruptedException { - repoOwner = Util.fixEmptyAndTrim(repoOwner); - if (repoOwner == null) { - return new ListBoxModel(); - } - if (context == null && !Jenkins.get().hasPermission(Jenkins.ADMINISTER) || - context != null && !context.hasPermission(Item.EXTENDED_READ)) { - return new ListBoxModel(); // not supposed to be seeing this form - } - if (context != null && !context.hasPermission(CredentialsProvider.USE_ITEM)) { - return new ListBoxModel(); // not permitted to try connecting with these credentials - } - - String serverUrlFallback = BitbucketCloudEndpoint.SERVER_URL; - // if at least one bitbucket server is configured use it instead of bitbucket cloud - if(BitbucketEndpointConfiguration.get().getEndpointItems().size() > 0){ - serverUrlFallback = BitbucketEndpointConfiguration.get().getEndpointItems().get(0).value; - } - - serverUrl = StringUtils.defaultIfBlank(serverUrl, serverUrlFallback); - ListBoxModel result = new ListBoxModel(); - StandardCredentials credentials = BitbucketCredentials.lookupCredentials( - serverUrl, - context, - credentialsId, - StandardCredentials.class - ); - - BitbucketAuthenticator authenticator = AuthenticationTokens.convert(BitbucketAuthenticator.authenticationContext(serverUrl), credentials); - - try { - BitbucketApi bitbucket = BitbucketApiFactory.newInstance(serverUrl, authenticator, repoOwner, null, null); + BitbucketSupplier listBoxModelSupplier = bitbucket -> { + ListBoxModel result = new ListBoxModel(); BitbucketTeam team = bitbucket.getTeam(); List repositories = - bitbucket.getRepositories(team != null ? null : UserRoleInRepository.CONTRIBUTOR); + bitbucket.getRepositories(team != null ? null : UserRoleInRepository.CONTRIBUTOR); if (repositories.isEmpty()) { throw FormFillFailure.error(Messages.BitbucketSCMSource_NoMatchingOwner(repoOwner)).withSelectionCleared(); } @@ -1332,29 +1393,21 @@ public ListBoxModel doFillRepositoryItems(@AncestorInPath SCMSourceOwner context result.add(repo.getRepositoryName()); } return result; - } catch (FormFillFailure | OutOfMemoryError e) { - throw e; - } catch (IOException e) { - if (e instanceof BitbucketRequestException) { - if (((BitbucketRequestException) e).getHttpCode() == 401) { - throw FormFillFailure.error(credentials == null - ? Messages.BitbucketSCMSource_UnauthorizedAnonymous(repoOwner) - : Messages.BitbucketSCMSource_UnauthorizedOwner(repoOwner)).withSelectionCleared(); - } - } else if (e.getCause() instanceof BitbucketRequestException) { - if (((BitbucketRequestException) e.getCause()).getHttpCode() == 401) { - throw FormFillFailure.error(credentials == null - ? Messages.BitbucketSCMSource_UnauthorizedAnonymous(repoOwner) - : Messages.BitbucketSCMSource_UnauthorizedOwner(repoOwner)).withSelectionCleared(); - } - } - LOGGER.log(Level.SEVERE, e.getMessage(), e); - throw FormFillFailure.error(e.getMessage()); - } catch (Throwable e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - throw FormFillFailure.error(e.getMessage()); - } + }; + return getFromBitbucket(context, serverUrl, credentialsId, repoOwner, null, listBoxModelSupplier); } + + @SuppressWarnings("unused") // used By stapler + public ListBoxModel doFillMirrorIdItems(@AncestorInPath SCMSourceOwner context, + @QueryParameter String serverUrl, + @QueryParameter String credentialsId, + @QueryParameter String repoOwner, + @QueryParameter String repository) + throws FormFillFailure { + + return getFromBitbucket(context, serverUrl, credentialsId, repoOwner, repository, MirrorListSupplier.INSTANCE); + } + @NonNull @Override protected SCMHeadCategory[] createCategories() { @@ -1518,7 +1571,7 @@ public SCMRevision create(@NonNull SCMHead head, PullRequestSCMHead prHead = (PullRequestSCMHead) head; SCMHead targetHead = prHead.getTarget(); - return new PullRequestSCMRevision<>( // + return new PullRequestSCMRevision( // prHead, // new BitbucketGitSCMRevision(targetHead, targetCommit), // new BitbucketGitSCMRevision(prHead, sourceCommit)); diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSourceBuilder.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSourceBuilder.java index e8fc04e68..cd080dbf2 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSourceBuilder.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSourceBuilder.java @@ -49,6 +49,11 @@ public class BitbucketSCMSourceBuilder extends SCMSourceBuilder branchWithHashes; + + public FallbackToOtherRepositoryGitSCMExtension( + String cloneLink, + String remoteName, + List branchWithHashes + ) { + this.cloneLink = cloneLink; + this.remoteName = remoteName; + this.branchWithHashes = branchWithHashes; + } + + @Override + public Revision decorateRevisionToBuild( + GitSCM scm, + Run build, + GitClient git, + TaskListener listener, + Revision marked, + Revision rev + ) throws InterruptedException { + List refSpecs = branchWithHashes.stream() + .filter(branchWithHash -> !commitExists(git, branchWithHash.getHash())) + .map(branchWithHash -> { + String branch = branchWithHash.getBranch(); + return new RefSpec("+refs/heads/" + branch + ":refs/remotes/" + remoteName + "/" + branch); + }) + .collect(Collectors.toList()); + + if (!refSpecs.isEmpty()) { + FetchCommand fetchCommand = git.fetch_(); + URIish remote; + try { + remote = new URIish(cloneLink); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + fetchCommand.from(remote, refSpecs).execute(); + } + return rev; + } + + private static boolean commitExists(GitClient git, String sha1) { + try { + git.revParse(sha1); + return true; + } catch (GitException ignored) { + return false; + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/MirrorListSupplier.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/MirrorListSupplier.java new file mode 100644 index 000000000..020f7f667 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/MirrorListSupplier.java @@ -0,0 +1,27 @@ +package com.cloudbees.jenkins.plugins.bitbucket; + +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApi; +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketMirrorServer; +import com.cloudbees.jenkins.plugins.bitbucket.server.client.BitbucketServerAPIClient; +import hudson.util.ListBoxModel; +import java.io.IOException; +import java.util.List; + +public class MirrorListSupplier implements BitbucketApiUtils.BitbucketSupplier { + + public static final MirrorListSupplier INSTANCE = new MirrorListSupplier(); + + @Override + public ListBoxModel get(BitbucketApi bitbucketApi) throws IOException, InterruptedException { + ListBoxModel result = new ListBoxModel(new ListBoxModel.Option("Primary server", "")); + if (bitbucketApi instanceof BitbucketServerAPIClient) { + BitbucketServerAPIClient bitbucketServerAPIClient = (BitbucketServerAPIClient) bitbucketApi; + List mirrors = bitbucketServerAPIClient.getMirrors(); + for (BitbucketMirrorServer mirror : mirrors) { + result.add(new ListBoxModel.Option(mirror.getName(), mirror.getId())); + } + } + return result; + + } +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/PullRequestSCMHead.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/PullRequestSCMHead.java index 00ccd37cf..d3a3162af 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/PullRequestSCMHead.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/PullRequestSCMHead.java @@ -252,7 +252,7 @@ public PullRequestSCMHead migrate(@NonNull BitbucketSCMSource source, @NonNull F public SCMRevision migrate(@NonNull BitbucketSCMSource source, @NonNull AbstractGitSCMSource.SCMRevisionImpl revision) { PullRequestSCMHead head = migrate(source, (FixLegacy) revision.getHead()); - return head != null ? new PullRequestSCMRevision<>(head, + return head != null ? new PullRequestSCMRevision(head, // ChangeRequestCheckoutStrategy.HEAD means we ignore the target revision, // so we can leave it null as a placeholder new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), null), diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/PullRequestSCMRevision.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/PullRequestSCMRevision.java index 15e4185a8..7831f1269 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/PullRequestSCMRevision.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/PullRequestSCMRevision.java @@ -25,7 +25,7 @@ package com.cloudbees.jenkins.plugins.bitbucket; import edu.umd.cs.findbugs.annotations.NonNull; -import jenkins.scm.api.SCMRevision; +import jenkins.plugins.git.AbstractGitSCMSource; import jenkins.scm.api.mixin.ChangeRequestCheckoutStrategy; import jenkins.scm.api.mixin.ChangeRequestSCMRevision; @@ -34,7 +34,7 @@ * * @since 2.2.0 */ -public class PullRequestSCMRevision extends ChangeRequestSCMRevision { +public class PullRequestSCMRevision extends ChangeRequestSCMRevision { /** * Standardize serialization. @@ -45,7 +45,7 @@ public class PullRequestSCMRevision extends ChangeRequest * The pull head revision. */ @NonNull - private final R pull; + private final AbstractGitSCMSource.SCMRevisionImpl pull; /** * Constructor. @@ -54,7 +54,7 @@ public class PullRequestSCMRevision extends ChangeRequest * @param target the target revision. * @param pull the pull revision. */ - public PullRequestSCMRevision(@NonNull PullRequestSCMHead head, @NonNull R target, @NonNull R pull) { + public PullRequestSCMRevision(@NonNull PullRequestSCMHead head, @NonNull AbstractGitSCMSource.SCMRevisionImpl target, @NonNull AbstractGitSCMSource.SCMRevisionImpl pull) { super(head, target); this.pull = pull; } @@ -65,7 +65,7 @@ public PullRequestSCMRevision(@NonNull PullRequestSCMHead head, @NonNull R targe * @return the pull revision. */ @NonNull - public R getPull() { + public AbstractGitSCMSource.SCMRevisionImpl getPull() { return pull; } @@ -81,6 +81,10 @@ public boolean equivalent(ChangeRequestSCMRevision o) { return getHead().equals(other.getHead()) && pull.equals(other.pull); } + public AbstractGitSCMSource.SCMRevisionImpl getTargetImpl() { + return (AbstractGitSCMSource.SCMRevisionImpl) getTarget(); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/SCMHeadWithOwnerAndRepo.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/SCMHeadWithOwnerAndRepo.java index 1988facc1..b94a51300 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/SCMHeadWithOwnerAndRepo.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/SCMHeadWithOwnerAndRepo.java @@ -160,7 +160,7 @@ public PullRequestSCMHead migrate(@NonNull BitbucketSCMSource source, @NonNull P public SCMRevision migrate(@NonNull BitbucketSCMSource source, @NonNull AbstractGitSCMSource.SCMRevisionImpl revision) { PullRequestSCMHead head = migrate(source, (PR) revision.getHead()); - return head != null ? new PullRequestSCMRevision<>(head, + return head != null ? new PullRequestSCMRevision(head, // ChangeRequestCheckoutStrategy.HEAD means we ignore the target revision, // so we can leave it null as a placeholder new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), null), diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketApi.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketApi.java index db3df153e..891369d9c 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketApi.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketApi.java @@ -57,21 +57,6 @@ public interface BitbucketApi { @CheckForNull String getRepositoryName(); - /** - * Returns the URI of the repository. - * - * @param protocol the protocol to access the repository with. - * @param cloneLink the actual clone link for the repository as sent by the server, or {@code null} if unknown. - * @param owner the owner - * @param repository the repository. - * @return the repository URI. - */ - @NonNull - String getRepositoryUri(@NonNull BitbucketRepositoryProtocol protocol, - @CheckForNull String cloneLink, - @NonNull String owner, - @NonNull String repository); - /** * Returns the pull requests in the repository. * diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketMirrorServer.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketMirrorServer.java new file mode 100644 index 000000000..dfec27c0f --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketMirrorServer.java @@ -0,0 +1,38 @@ +package com.cloudbees.jenkins.plugins.bitbucket.api; + +/** + * Represents a Bitbucket mirror. + */ +public class BitbucketMirrorServer { + + private String id; + + private String name; + + private boolean enabled; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketMirroredRepository.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketMirroredRepository.java new file mode 100644 index 000000000..34909059b --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketMirroredRepository.java @@ -0,0 +1,28 @@ +package com.cloudbees.jenkins.plugins.bitbucket.api; + +import java.util.List; +import java.util.Map; + +public class BitbucketMirroredRepository { + + private boolean available; + + private Map> links; + + public boolean isAvailable() { + return available; + } + + public void setAvailable(boolean available) { + this.available = available; + } + + public Map> getLinks() { + return links; + } + + public void setLinks(Map> links) { + this.links = links; + } + +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketMirroredRepositoryDescriptor.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketMirroredRepositoryDescriptor.java new file mode 100644 index 000000000..61bc0d251 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketMirroredRepositoryDescriptor.java @@ -0,0 +1,30 @@ +package com.cloudbees.jenkins.plugins.bitbucket.api; + +import java.util.List; +import java.util.Map; + +/** + * Represents a Bitbucket mirror descriptor. + */ +public class BitbucketMirroredRepositoryDescriptor { + + private BitbucketMirrorServer mirrorServer; + + private Map> links; + + public BitbucketMirrorServer getMirrorServer() { + return mirrorServer; + } + + public void setMirrorServer(BitbucketMirrorServer mirrorServer) { + this.mirrorServer = mirrorServer; + } + + public Map> getLinks() { + return links; + } + + public void setLinks(Map> links) { + this.links = links; + } +} 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 cf7d23f29..4612f4d95 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 @@ -33,7 +33,6 @@ import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketException; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketPullRequest; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepository; -import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryProtocol; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRequestException; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketTeam; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketWebHook; @@ -231,32 +230,6 @@ public String getRepositoryName() { return repositoryName; } - /** - * {@inheritDoc} - */ - @NonNull - @Override - public String getRepositoryUri(@NonNull BitbucketRepositoryProtocol protocol, - @CheckForNull String cloneLink, - @NonNull String owner, - @NonNull String repository) { - // ignore port override on Cloud - switch (protocol) { - case HTTP: - if (authenticator != null) { - String username = authenticator.getUserUri(); - if (!username.isEmpty()) { - return "https://" + username + "@bitbucket.org/" + owner + "/" + repository + ".git"; - } - } - return "https://bitbucket.org/" + owner + "/" + repository + ".git"; - case SSH: - return "git@bitbucket.org:" + owner + "/" + repository + ".git"; - default: - throw new IllegalArgumentException("Unsupported repository protocol: " + protocol); - } - } - /** * {@inheritDoc} */ diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/HookEventType.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/HookEventType.java index 4983d8903..734781947 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/HookEventType.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/HookEventType.java @@ -67,6 +67,12 @@ public enum HookEventType { */ SERVER_REFS_CHANGED("repo:refs_changed", NativeServerPushHookProcessor.class), + /** + * @see Eventpayload-repo-mirr-syn + * @since Bitbucket Server 6.5 + */ + SERVER_MIRROR_REPO_SYNCHRONIZED("mirror:repo_synchronized", NativeServerPushHookProcessor.class), + /** * @see Eventpayload-Opened * @since Bitbucket Server 5.4 diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/NativeServerPullRequestHookProcessor.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/NativeServerPullRequestHookProcessor.java index 67061ec59..11f6b1ceb 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/NativeServerPullRequestHookProcessor.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/NativeServerPullRequestHookProcessor.java @@ -126,8 +126,15 @@ protected Map heads(@NonNull BitbucketSCMSource source) { final String originalBranchName = pullRequest.getSource().getBranch().getName(); final String branchName = String.format("PR-%s%s", pullRequest.getId(), strategies.size() > 1 ? "-" + Ascii.toLowerCase(strategy.name()) : ""); - final PullRequestSCMHead head = new PullRequestSCMHead(branchName, source.getRepoOwner(), - source.getRepository(), originalBranchName, pullRequest, headOrigin, strategy); + final PullRequestSCMHead head = new PullRequestSCMHead( + branchName, + sourceRepo.getOwnerName(), + sourceRepo.getRepositoryName(), + originalBranchName, + pullRequest, + headOrigin, + strategy + ); switch (getType()) { case CREATED: @@ -135,7 +142,7 @@ protected Map heads(@NonNull BitbucketSCMSource source) { final String targetHash = pullRequest.getDestination().getCommit().getHash(); final String pullHash = pullRequest.getSource().getCommit().getHash(); result.put(head, - new PullRequestSCMRevision<>(head, + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), targetHash), new AbstractGitSCMSource.SCMRevisionImpl(head, pullHash))); break; diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/NativeServerPushHookProcessor.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/NativeServerPushHookProcessor.java index e523dec9f..0c4cf27de 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/NativeServerPushHookProcessor.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/NativeServerPushHookProcessor.java @@ -34,6 +34,8 @@ import com.cloudbees.jenkins.plugins.bitbucket.server.client.BitbucketServerAPIClient; import com.cloudbees.jenkins.plugins.bitbucket.server.client.pullrequest.BitbucketServerPullRequest; import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerRepository; +import com.cloudbees.jenkins.plugins.bitbucket.server.events.NativeServerChange; +import com.cloudbees.jenkins.plugins.bitbucket.server.events.NativeServerMirrorRepoSynchronizedEvent; import com.cloudbees.jenkins.plugins.bitbucket.server.events.NativeServerRefsChangedEvent; import com.google.common.base.Ascii; import com.google.common.collect.HashMultimap; @@ -78,25 +80,39 @@ public void process(HookEventType hookEvent, String payload, BitbucketType insta return; } - final NativeServerRefsChangedEvent refsChangedEvent; + final BitbucketServerRepository repository; + final List changes; + final String mirrorId; try { - refsChangedEvent = JsonParser.toJava(payload, NativeServerRefsChangedEvent.class); + if (hookEvent == HookEventType.SERVER_REFS_CHANGED) { + final NativeServerRefsChangedEvent event = JsonParser.toJava(payload, NativeServerRefsChangedEvent.class); + repository = event.getRepository(); + changes = event.getChanges(); + mirrorId = null; + } else if (hookEvent == HookEventType.SERVER_MIRROR_REPO_SYNCHRONIZED) { + final NativeServerMirrorRepoSynchronizedEvent event = JsonParser.toJava(payload, NativeServerMirrorRepoSynchronizedEvent.class); + repository = event.getRepository(); + changes = event.getChanges(); + mirrorId = event.getMirrorServer().getId(); + } else { + throw new UnsupportedOperationException("Unsupported hook event " + hookEvent); + } } catch (final IOException e) { LOGGER.log(Level.SEVERE, "Can not read hook payload", e); return; } - final String owner = refsChangedEvent.getRepository().getOwnerName(); - final String repository = refsChangedEvent.getRepository().getRepositoryName(); - if (refsChangedEvent.getChanges().isEmpty()) { + if (changes.isEmpty()) { + final String owner = repository.getOwnerName(); + final String repositoryName = repository.getRepositoryName(); LOGGER.log(Level.INFO, "Received hook from Bitbucket. Processing push event on {0}/{1}", - new Object[] { owner, repository }); - scmSourceReIndex(owner, repository); + new Object[] { owner, repositoryName }); + scmSourceReIndex(owner, repositoryName); return; } - final Multimap events = HashMultimap.create(); - for (final NativeServerRefsChangedEvent.Change change : refsChangedEvent.getChanges()) { + final Multimap events = HashMultimap.create(); + for (final NativeServerChange change : changes) { final String type = change.getType(); if ("UPDATE".equals(type)) { events.put(SCMEvent.Type.UPDATED, change); @@ -110,23 +126,26 @@ public void process(HookEventType hookEvent, String payload, BitbucketType insta } for (final SCMEvent.Type type : events.keySet()) { - SCMHeadEvent.fireLater(new HeadEvent(serverUrl, type, events.get(type), origin, refsChangedEvent), BitbucketSCMSource.getEventDelaySeconds(), TimeUnit.SECONDS); + HeadEvent headEvent = new HeadEvent(serverUrl, type, events.get(type), origin, repository, mirrorId); + SCMHeadEvent.fireLater(headEvent, BitbucketSCMSource.getEventDelaySeconds(), TimeUnit.SECONDS); } } - private static final class HeadEvent extends NativeServerHeadEvent> implements HasPullRequests { - private final NativeServerRefsChangedEvent refsChangedEvent; + private static final class HeadEvent extends NativeServerHeadEvent> implements HasPullRequests { + private final BitbucketServerRepository repository; private final Map> cachedPullRequests = new HashMap<>(); + private final String mirrorId; - HeadEvent(String serverUrl, Type type, Collection payload, String origin, - NativeServerRefsChangedEvent refsChangedEvent) { + HeadEvent(String serverUrl, Type type, Collection payload, String origin, + BitbucketServerRepository repository, String mirrorId) { super(serverUrl, type, payload, origin); - this.refsChangedEvent = refsChangedEvent; + this.repository = repository; + this.mirrorId = mirrorId; } @Override protected BitbucketServerRepository getRepository() { - return refsChangedEvent.getRepository(); + return repository; } @Override @@ -146,7 +165,7 @@ protected Map heads(BitbucketSCMSource source) { } private void addBranchesAndTags(BitbucketSCMSource src, Map result) { - for (final NativeServerRefsChangedEvent.Change change : getPayload()) { + for (final NativeServerChange change : getPayload()) { String refType = change.getRef().getType(); if ("BRANCH".equals(refType)) { @@ -179,12 +198,12 @@ private void addPullRequests(BitbucketSCMSource src, Map r final String sourceOwnerName = src.getRepoOwner(); final String sourceRepoName = src.getRepository(); - final BitbucketServerRepository eventRepo = refsChangedEvent.getRepository(); + final BitbucketServerRepository eventRepo = repository; final SCMHeadOrigin headOrigin = src.originOf(eventRepo.getOwnerName(), eventRepo.getRepositoryName()); final Set strategies = headOrigin == SCMHeadOrigin.DEFAULT ? ctx.originPRStrategies() : ctx.forkPRStrategies(); - for (final NativeServerRefsChangedEvent.Change change : getPayload()) { + for (final NativeServerChange change : getPayload()) { if (!"BRANCH".equals(change.getRef().getType())) { LOGGER.log(Level.INFO, "Received event for unknown ref type {0} of ref {1}", new Object[] { change.getRef().getType(), change.getRef().getDisplayId() }); @@ -209,14 +228,22 @@ private void addPullRequests(BitbucketSCMSource src, Map r final String branchName = String.format("PR-%s%s", pullRequest.getId(), strategies.size() > 1 ? "-" + Ascii.toLowerCase(strategy.name()) : ""); - final PullRequestSCMHead head = new PullRequestSCMHead(branchName, sourceOwnerName, - sourceRepoName, originalBranchName, pullRequest, headOrigin, strategy); + final BitbucketServerRepository pullRequestRepository = pullRequest.getSource().getRepository(); + final PullRequestSCMHead head = new PullRequestSCMHead( + branchName, + pullRequestRepository.getOwnerName(), + pullRequestRepository.getRepositoryName(), + originalBranchName, + pullRequest, + headOrigin, + strategy + ); final String targetHash = pullRequest.getDestination().getCommit().getHash(); final String pullHash = pullRequest.getSource().getCommit().getHash(); result.put(head, - new PullRequestSCMRevision<>(head, + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), targetHash), new AbstractGitSCMSource.SCMRevisionImpl(head, pullHash))); } @@ -224,7 +251,7 @@ private void addPullRequests(BitbucketSCMSource src, Map r } } - private Map getPullRequests(BitbucketSCMSource src, NativeServerRefsChangedEvent.Change change) + private Map getPullRequests(BitbucketSCMSource src, NativeServerChange change) throws InterruptedException { Map pullRequests; @@ -240,9 +267,9 @@ private Map getPullRequests(BitbucketSCMSour } private Map loadPullRequests(BitbucketSCMSource src, - NativeServerRefsChangedEvent.Change change) throws InterruptedException { + NativeServerChange change) throws InterruptedException { - final BitbucketServerRepository eventRepo = refsChangedEvent.getRepository(); + final BitbucketServerRepository eventRepo = repository; final BitbucketServerAPIClient api = (BitbucketServerAPIClient) src .buildBitbucketClient(eventRepo.getOwnerName(), eventRepo.getRepositoryName()); @@ -278,13 +305,19 @@ private Map loadPullRequests(BitbucketSCMSou @Override public Collection getPullRequests(BitbucketSCMSource src) throws InterruptedException { List prs = new ArrayList<>(); - for (final NativeServerRefsChangedEvent.Change change : getPayload()) { + for (final NativeServerChange change : getPayload()) { Map prsForChange = getPullRequests(src, change); prs.addAll(prsForChange.values()); } return prs; } + + @Override + protected boolean eventMatchesRepo(BitbucketSCMSource source) { + return Objects.equals(source.getMirrorId(), this.mirrorId) && super.eventMatchesRepo(source); + } + } private static final class CacheKey { @@ -293,7 +326,7 @@ private static final class CacheKey { @CheckForNull private final String credentialsId; - CacheKey(BitbucketSCMSource src, NativeServerRefsChangedEvent.Change change) { + CacheKey(BitbucketSCMSource src, NativeServerChange change) { this.refId = requireNonNull(change.getRefId()); this.credentialsId = src.getCredentialsId(); } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/PullRequestHookProcessor.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/PullRequestHookProcessor.java index ae1789fad..f146e1970 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/PullRequestHookProcessor.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/PullRequestHookProcessor.java @@ -212,28 +212,15 @@ public Map heads(@NonNull SCMSource source) { branchName = branchName + "-" + strategy.name().toLowerCase(Locale.ENGLISH); } String originalBranchName = pull.getSource().getBranch().getName(); - PullRequestSCMHead head; - if (instanceType == BitbucketType.CLOUD) { - head = new PullRequestSCMHead( - branchName, - pullRepoOwner, - pullRepository, - originalBranchName, - pull, - headOrigin, - strategy - ); - } else { - head = new PullRequestSCMHead( - branchName, - src.getRepoOwner(), - src.getRepository(), - originalBranchName, - pull, - headOrigin, - strategy - ); - } + PullRequestSCMHead head = new PullRequestSCMHead( + branchName, + pullRepoOwner, + pullRepository, + originalBranchName, + pull, + headOrigin, + strategy + ); if (hookEvent == PULL_REQUEST_DECLINED || hookEvent == PULL_REQUEST_MERGED) { // special case for repo being deleted result.put(head, null); @@ -241,7 +228,7 @@ public Map heads(@NonNull SCMSource source) { String targetHash = pull.getDestination().getCommit().getHash(); String pullHash = pull.getSource().getCommit().getHash(); - SCMRevision revision = new PullRequestSCMRevision<>(head, + SCMRevision revision = new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), targetHash), new AbstractGitSCMSource.SCMRevisionImpl(head, pullHash) ); diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfiguration.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfiguration.java index a673c1866..bbd14c4de 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfiguration.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfiguration.java @@ -69,10 +69,17 @@ public class WebhookConfiguration { // only on v5.10 and above HookEventType.SERVER_PULL_REQUEST_MODIFIED.getKey(), HookEventType.SERVER_PULL_REQUEST_REVIEWER_UPDATED.getKey(), + // only on v6.5 and above + HookEventType.SERVER_MIRROR_REPO_SYNCHRONIZED.getKey(), // only on v7.x and above HookEventType.SERVER_PULL_REQUEST_FROM_REF_UPDATED.getKey() )); + /** + * The list of events available in Bitbucket Server v6.5+. + */ + private static final List NATIVE_SERVER_EVENTS_v6_5 = Collections.unmodifiableList(NATIVE_SERVER_EVENTS_v7.subList(0, 8)); + /** * The list of events available in Bitbucket Server v6.x. Applies to v5.10+. */ @@ -222,6 +229,8 @@ private static List getNativeServerEvents(String serverUrl) { // for it to have its // own list return NATIVE_SERVER_EVENTS_v6; + case VERSION_6_5: + return NATIVE_SERVER_EVENTS_v6_5; case VERSION_7: default: return NATIVE_SERVER_EVENTS_v7; diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/BitbucketServerVersion.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/BitbucketServerVersion.java index 399a70e0d..a09381adf 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/BitbucketServerVersion.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/BitbucketServerVersion.java @@ -27,7 +27,8 @@ public enum BitbucketServerVersion implements ModelObject { VERSION_7("Bitbucket v7.x (and later)"), - VERSION_6("Bitbucket v6.x"), + VERSION_6_5("Bitbucket v6.5 to v6.10"), + VERSION_6("Bitbucket v6.0 to v6.4"), VERSION_5_10("Bitbucket v5.10 to v5.16"), VERSION_5("Bitbucket v5.9 (and earlier)"); 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 4cda7bed2..93f0c4c45 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 @@ -28,9 +28,11 @@ import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketAuthenticator; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketBuildStatus; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketCommit; +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketMirrorServer; +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketMirroredRepository; +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketMirroredRepositoryDescriptor; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketPullRequest; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepository; -import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryProtocol; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRequestException; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketTeam; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketWebHook; @@ -45,6 +47,8 @@ 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.mirror.BitbucketMirrorServerDescriptors; +import com.cloudbees.jenkins.plugins.bitbucket.server.client.mirror.BitbucketMirroredRepositoryDescriptors; 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; @@ -72,7 +76,6 @@ import java.net.InetSocketAddress; import java.net.Proxy; import java.net.URI; -import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; @@ -81,7 +84,6 @@ import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.concurrent.Callable; import java.util.function.Predicate; import java.util.logging.Level; @@ -158,6 +160,10 @@ public class BitbucketServerAPIClient implements BitbucketApi { private static final String WEBHOOK_REPOSITORY_CONFIG_PATH = WEBHOOK_REPOSITORY_PATH + "/{id}"; private static final String API_COMMIT_STATUS_PATH = "/rest/build-status/1.0/commits{/hash}"; + + private static final String API_MIRRORS_FOR_REPO_PATH = "/rest/mirroring/1.0/repos/{id}/mirrors"; + private static final String API_MIRRORS_PATH = "/rest/mirroring/1.0/mirrorServers"; + private static final Integer DEFAULT_PAGE_LIMIT = 200; private static final int API_RATE_LIMIT_STATUS_CODE = 429; private static final Duration API_RATE_LIMIT_INITIAL_SLEEP = Main.isUnitTest ? Duration.ofMillis(100) : Duration.ofSeconds(5); @@ -245,55 +251,6 @@ public String getRepositoryName() { return repositoryName; } - /** - * {@inheritDoc} - */ - @NonNull - @Override - public String getRepositoryUri(@NonNull BitbucketRepositoryProtocol protocol, - @CheckForNull String cloneLink, - @NonNull String owner, - @NonNull String repository) { - URI baseUri; - try { - baseUri = new URI(baseURL); - } catch (URISyntaxException e) { - throw new IllegalStateException("Server URL is not a valid URI", e); - } - - UriTemplate template = UriTemplate.fromTemplate("{scheme}://{+authority}{+path}{/owner,repository}.git"); - template.set("owner", owner); - template.set("repository", repository); - - switch (protocol) { - case HTTP: - template.set("scheme", baseUri.getScheme()); - template.set("authority", baseUri.getRawAuthority()); - template.set("path", Objects.toString(baseUri.getRawPath(), "") + "/scm"); - break; - case SSH: - template.set("scheme", BitbucketRepositoryProtocol.SSH.getType()); - template.set("authority", "git@" + baseUri.getHost()); - if (cloneLink != null) { - try { - URI cloneLinkUri = new URI(cloneLink); - if (cloneLinkUri.getScheme() != null) { - template.set("scheme", cloneLinkUri.getScheme()); - } - if (cloneLinkUri.getRawAuthority() != null) { - template.set("authority", cloneLinkUri.getRawAuthority()); - } - } catch (@SuppressWarnings("unused") URISyntaxException ignored) { - // fall through - } - } - break; - default: - throw new IllegalArgumentException("Unsupported repository protocol: " + protocol); - } - return template.expand(); - } - /** * {@inheritDoc} */ @@ -499,6 +456,54 @@ public BitbucketRepository getRepository() throws IOException, InterruptedExcept } } + /** + * Returns the mirror servers. + * + * @return the mirror servers + * @throws IOException if there was a network communications error. + * @throws InterruptedException if interrupted while waiting on remote communications. + */ + @NonNull + public List getMirrors() throws IOException, InterruptedException { + UriTemplate uriTemplate = UriTemplate + .fromTemplate(API_MIRRORS_PATH); + return getResources(uriTemplate, BitbucketMirrorServerDescriptors.class); + } + + /** + * Returns the repository mirror descriptors. + * + * @return the repository mirror descriptors for given repository id. + * @throws IOException if there was a network communications error. + * @throws InterruptedException if interrupted while waiting on remote communications. + */ + @NonNull + public List getMirrors(@NonNull Long repositoryId) throws IOException, InterruptedException { + UriTemplate uriTemplate = UriTemplate + .fromTemplate(API_MIRRORS_FOR_REPO_PATH) + .set("id", repositoryId); + return getResources(uriTemplate, BitbucketMirroredRepositoryDescriptors.class); + } + + /** + * Retrieves all available clone urls for the specified repository. + * + * @param url mirror repository self-url + * @return all available clone urls for the specified repository. + * @throws IOException if there was a network communications error. + * @throws InterruptedException if interrupted while waiting on remote communications. + */ + @NonNull + public BitbucketMirroredRepository getMirroredRepository(@NonNull String url) throws IOException, InterruptedException { + HttpGet httpget = new HttpGet(url); + var response = getRequest(httpget); + try { + return JsonParser.toJava(response, BitbucketMirroredRepository.class); + } catch (IOException e) { + throw new IOException("I/O error when accessing URL: " + url, e); + } + } + /** * {@inheritDoc} */ @@ -945,6 +950,10 @@ private V getResource(UriTemplate template, Class { +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/mirror/BitbucketMirroredRepositoryDescriptors.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/mirror/BitbucketMirroredRepositoryDescriptors.java new file mode 100644 index 000000000..5d12dfaa7 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/mirror/BitbucketMirroredRepositoryDescriptors.java @@ -0,0 +1,7 @@ +package com.cloudbees.jenkins.plugins.bitbucket.server.client.mirror; + +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketMirroredRepositoryDescriptor; +import com.cloudbees.jenkins.plugins.bitbucket.server.client.PagedApiResponse; + +public class BitbucketMirroredRepositoryDescriptors extends PagedApiResponse { +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/BitbucketServerMirrorServer.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/BitbucketServerMirrorServer.java new file mode 100644 index 000000000..52619a275 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/BitbucketServerMirrorServer.java @@ -0,0 +1,21 @@ +package com.cloudbees.jenkins.plugins.bitbucket.server.events; + +public class BitbucketServerMirrorServer { + private String id, name; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerChange.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerChange.java new file mode 100644 index 000000000..0f6d537d6 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerChange.java @@ -0,0 +1,46 @@ +package com.cloudbees.jenkins.plugins.bitbucket.server.events; + +public class NativeServerChange { + private NativeServerRef ref; + private String refId, fromHash, toHash, type; + + public NativeServerRef getRef() { + return ref; + } + + public void setRef(NativeServerRef ref) { + this.ref = ref; + } + + public String getRefId() { + return refId; + } + + public void setRefId(String refId) { + this.refId = refId; + } + + public String getFromHash() { + return fromHash; + } + + public void setFromHash(String fromHash) { + this.fromHash = fromHash; + } + + public String getToHash() { + return toHash; + } + + public void setToHash(String toHash) { + this.toHash = toHash; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerMirrorRepoSynchronizedEvent.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerMirrorRepoSynchronizedEvent.java new file mode 100644 index 000000000..7a7e372e9 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerMirrorRepoSynchronizedEvent.java @@ -0,0 +1,25 @@ +package com.cloudbees.jenkins.plugins.bitbucket.server.events; + +import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerRepository; +import java.util.Collections; +import java.util.List; + +public class NativeServerMirrorRepoSynchronizedEvent { + private BitbucketServerMirrorServer mirrorServer; + + private BitbucketServerRepository repository; + private List changes; + + public BitbucketServerMirrorServer getMirrorServer() { + return mirrorServer; + } + + public BitbucketServerRepository getRepository() { + return repository; + } + + public List getChanges() { + return changes == null ? Collections.emptyList() : Collections.unmodifiableList(changes); + } + +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerRef.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerRef.java new file mode 100644 index 000000000..60144649b --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerRef.java @@ -0,0 +1,29 @@ +package com.cloudbees.jenkins.plugins.bitbucket.server.events; + +public class NativeServerRef { + private String id, displayId, type; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDisplayId() { + return displayId; + } + + public void setDisplayId(String displayId) { + this.displayId = displayId; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerRefsChangedEvent.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerRefsChangedEvent.java index e4547e173..f28e204a7 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerRefsChangedEvent.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/events/NativeServerRefsChangedEvent.java @@ -30,86 +30,14 @@ public class NativeServerRefsChangedEvent { private BitbucketServerRepository repository; - private List changes; + private List changes; public BitbucketServerRepository getRepository() { return repository; } - public List getChanges() { - return changes == null ? Collections. emptyList() : Collections.unmodifiableList(changes); - } - - public static class Change { - private Ref ref; - private String refId, fromHash, toHash, type; - - public Ref getRef() { - return ref; - } - - public void setRef(Ref ref) { - this.ref = ref; - } - - public String getRefId() { - return refId; - } - - public void setRefId(String refId) { - this.refId = refId; + public List getChanges() { + return changes == null ? Collections. emptyList() : Collections.unmodifiableList(changes); } - public String getFromHash() { - return fromHash; - } - - public void setFromHash(String fromHash) { - this.fromHash = fromHash; - } - - public String getToHash() { - return toHash; - } - - public void setToHash(String toHash) { - this.toHash = toHash; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - } - - public static class Ref { - private String id, displayId, type; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getDisplayId() { - return displayId; - } - - public void setDisplayId(String displayId) { - this.displayId = displayId; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - } } diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator/config.jelly b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator/config.jelly index e988fa82b..d4d66073d 100644 --- a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator/config.jelly +++ b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator/config.jelly @@ -22,6 +22,9 @@ + + + diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator/help-mirrorId.html b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator/help-mirrorId.html new file mode 100644 index 000000000..1b72ccdf3 --- /dev/null +++ b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator/help-mirrorId.html @@ -0,0 +1,3 @@ +
+ The location Jenkins should clone from. This can be the primary server or a mirror if one is available. +
diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource/config-detail.jelly b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource/config-detail.jelly index 5906d9cc3..4daa73707 100644 --- a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource/config-detail.jelly +++ b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource/config-detail.jelly @@ -12,6 +12,9 @@ + + + diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource/help-mirrorId.html b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource/help-mirrorId.html new file mode 100644 index 000000000..1b72ccdf3 --- /dev/null +++ b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource/help-mirrorId.html @@ -0,0 +1,3 @@ +
+ The location Jenkins should clone from. This can be the primary server or a mirror if one is available. +
diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint/help-webhookImplementation.html b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint/help-webhookImplementation.html index 4e6f493d0..94916270f 100644 --- a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint/help-webhookImplementation.html +++ b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint/help-webhookImplementation.html @@ -3,6 +3,7 @@
Plugin
The third party Webhook implementation provided by a plugin.
+
Please note cloning from mirror is not supported with this implementation.
Native
The native Webhook implementation available since Bitbucket Server 5.4.
diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketBuildStatusNotificationsTest.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketBuildStatusNotificationsTest.java index 49a4af20a..8bd4d9507 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketBuildStatusNotificationsTest.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketBuildStatusNotificationsTest.java @@ -29,7 +29,6 @@ import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketCommit; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketHref; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepository; -import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryProtocol; import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketCloudEndpoint; import com.cloudbees.jenkins.plugins.bitbucket.filesystem.BitbucketSCMFile; import hudson.model.Action; @@ -68,7 +67,6 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @@ -117,11 +115,6 @@ private WorkflowMultiBranchProject prepareFirstCheckoutCompletedInvisibleActionT when(api.resolveCommit(sampleRepo.head())).thenReturn(commit); when(commit.getDateMillis()).thenReturn(System.currentTimeMillis()); when(api.checkPathExists(Mockito.anyString(), eq(jenkinsfile))).thenReturn(true); - when(api.getRepositoryUri(any(BitbucketRepositoryProtocol.class), - anyString(), - eq(repoOwner), - eq(repositoryName))) - .thenReturn(sampleRepo.fileUrl()); BitbucketRepository repository = Mockito.mock(BitbucketRepository.class); when(api.getRepository()).thenReturn(repository); when(repository.getOwnerName()).thenReturn(repoOwner); diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketClientMockUtils.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketClientMockUtils.java index e358c0410..626ba96ef 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketClientMockUtils.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketClientMockUtils.java @@ -25,7 +25,6 @@ import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApi; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketHref; -import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryProtocol; import com.cloudbees.jenkins.plugins.bitbucket.client.BitbucketCloudApiClient; import com.cloudbees.jenkins.plugins.bitbucket.client.branch.BitbucketCloudAuthor; import com.cloudbees.jenkins.plugins.bitbucket.client.branch.BitbucketCloudBranch; @@ -46,9 +45,7 @@ import java.util.List; import jenkins.model.Jenkins; -import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -57,8 +54,6 @@ public class BitbucketClientMockUtils { public static BitbucketCloudApiClient getAPIClientMock(boolean includePullRequests, boolean includeWebHooks) throws IOException, InterruptedException { BitbucketCloudApiClient bitbucket = mock(BitbucketCloudApiClient.class); - when(bitbucket.getRepositoryUri(any(BitbucketRepositoryProtocol.class), nullable(String.class), - anyString(), anyString())).thenCallRealMethod(); // mock branches BitbucketCloudBranch branch1 = getBranch("branch1", "52fc8e220d77ec400f7fc96a91d2fd0bb1bc553a"); @@ -122,7 +117,7 @@ private static List getRepositories() { new BitbucketHref("https://api.bitbucket.org/2.0/repositories/amuniz/repo1") )); links.put("clone", Arrays.asList( - new BitbucketHref("https","https://bitbucket.org/amuniz/repo1.git"), + new BitbucketHref("http","https://bitbucket.org/amuniz/repo1.git"), new BitbucketHref("ssh","ssh://git@bitbucket.org/amuniz/repo1.git") )); r1.setLinks(links); @@ -133,10 +128,10 @@ private static List getRepositories() { new BitbucketHref("https://api.bitbucket.org/2.0/repositories/amuniz/repo2") )); links.put("clone", Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/amuniz/repo2.git"), + new BitbucketHref("http", "https://bitbucket.org/amuniz/repo2.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/amuniz/repo2.git") )); - r1.setLinks(links); + r2.setLinks(links); BitbucketCloudRepository r3 = new BitbucketCloudRepository(); // test mock hack to avoid a lot of harness code r3.setFullName("amuniz/test-repos"); @@ -145,10 +140,10 @@ private static List getRepositories() { new BitbucketHref("https://api.bitbucket.org/2.0/repositories/amuniz/test-repos") )); links.put("clone", Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/amuniz/test-repos.git"), + new BitbucketHref("http", "https://bitbucket.org/amuniz/test-repos.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/amuniz/test-repos.git") )); - r1.setLinks(links); + r3.setLinks(links); return Arrays.asList(r1, r2, r3); } @@ -164,6 +159,15 @@ private static void withMockGitRepos(BitbucketApi bitbucket) throws IOException, repo.setScm("git"); repo.setFullName("amuniz/test-repos"); repo.setPrivate(true); + HashMap> links = new HashMap<>(); + links.put("self", Collections.singletonList( + new BitbucketHref("https://api.bitbucket.org/2.0/repositories/amuniz/test-repos") + )); + links.put("clone", Arrays.asList( + new BitbucketHref("http", "https://bitbucket.org/amuniz/test-repos.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket.org/amuniz/test-repos.git") + )); + repo.setLinks(links); when(bitbucket.getRepository()).thenReturn(repo); } diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMBuilderTest.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMBuilderTest.java index 0e7b3831c..9f47279ec 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMBuilderTest.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMBuilderTest.java @@ -72,6 +72,7 @@ public void tearDown() throws IOException, InterruptedException { SystemCredentialsProvider.getInstance() .setDomainCredentialsMap(Collections.>emptyMap()); owner.delete(); + BitbucketMockApiFactory.clear(); } @Test @@ -85,18 +86,20 @@ public void given__cloud_branch_rev_anon__when__build__then__scmBuilt() throws E assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -143,18 +146,20 @@ public void given__cloud_branch_rev_userpass__when__build__then__scmBuilt() thro assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -201,18 +206,20 @@ public void given__cloud_branch_rev_userkey__when__build__then__scmBuilt() throw assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); - assertThat(instance.remote(), is("git@bitbucket.org:tester/test-repo.git")); + ), + List.of() + ); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -222,12 +229,12 @@ public void given__cloud_branch_rev_userkey__when__build__then__scmBuilt() throw UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/origin/test-branch")); - assertThat(config.getUrl(), is("git@bitbucket.org:tester/test-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/tester/test-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:tester/test-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/tester/test-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/test-branch")); @@ -257,18 +264,20 @@ public void given__cloud_branch_norev_anon__when__build__then__scmBuilt() throws assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -301,18 +310,20 @@ public void given__cloud_branch_norev_userpass__when__build__then__scmBuilt() th assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -345,18 +356,20 @@ public void given__cloud_branch_norev_userkey__when__build__then__scmBuilt() thr assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); - assertThat(instance.remote(), is("git@bitbucket.org:tester/test-repo.git")); + ), + List.of() + ); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -366,12 +379,12 @@ public void given__cloud_branch_norev_userkey__when__build__then__scmBuilt() thr UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/origin/test-branch")); - assertThat(config.getUrl(), is("git@bitbucket.org:tester/test-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/tester/test-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:tester/test-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/tester/test-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/test-branch")); @@ -392,18 +405,20 @@ public void given__server_branch_rev_anon__when__build__then__scmBuilt() throws assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -439,6 +454,69 @@ public void given__server_branch_rev_anon__when__build__then__scmBuilt() throws assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); } + @Test + public void given__server_withMirror_branch_rev_anon__when__build__then__scmBuilt() throws Exception { + source.setServerUrl("https://bitbucket.test"); + BranchSCMHead head = new BranchSCMHead("test-branch"); + AbstractGitSCMSource.SCMRevisionImpl revision = + new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe"); + BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, + head, revision, null); + assertThat(instance.credentialsId(), is(nullValue())); + assertThat(instance.head(), is(head)); + assertThat(instance.revision(), is(revision)); + assertThat(instance.scmSource(), is(source)); + assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", + instance.remote(), is("https://bitbucket.test")); + assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); + assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); + + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") + ), + List.of( + new BitbucketHref("http", "https://bitbucket-mirror.test/scm/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket-mirror.test:7999/tester/test-repo.git") + ) + ); + assertThat(instance.remote(), is("https://bitbucket-mirror.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); + + GitSCM actual = instance.build(); + assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); + assertThat(actual.getGitTool(), nullValue()); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); + UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); + assertThat(config.getName(), is("origin")); + assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/origin/test-branch")); + assertThat(config.getUrl(), is("https://bitbucket-mirror.test/scm/tester/test-repo.git")); + assertThat(config.getCredentialsId(), is(nullValue())); + RemoteConfig origin = actual.getRepositoryByName("origin"); + assertThat(origin, notNullValue()); + assertThat(origin.getURIs(), hasSize(1)); + assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket-mirror.test/scm/tester/test-repo.git")); + assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); + assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/test-branch")); + assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(actual.getExtensions(), containsInAnyOrder( + instanceOf(GitSCMSourceDefaults.class), + instanceOf(BuildChooserSetting.class) + )); + BuildChooserSetting chooser = getExtension(actual, BuildChooserSetting.class); + assertThat(chooser.getBuildChooser(), instanceOf(AbstractGitSCMSource.SpecificRevisionBuildChooser.class)); + AbstractGitSCMSource.SpecificRevisionBuildChooser revChooser = + (AbstractGitSCMSource.SpecificRevisionBuildChooser) chooser.getBuildChooser(); + Collection revisions = revChooser + .getCandidateRevisions(false, "test-branch", Mockito.mock(GitClient.class), new LogTaskListener( + Logger.getAnonymousLogger(), Level.FINEST), null, null); + assertThat(revisions, hasSize(1)); + assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); + } @Test public void given__server_branch_rev_userpass__when__build__then__scmBuilt() throws Exception { @@ -452,18 +530,20 @@ public void given__server_branch_rev_userpass__when__build__then__scmBuilt() thr assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -511,18 +591,20 @@ public void given__server_branch_rev_userkey__when__build__then__scmBuilt() thro assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -570,19 +652,21 @@ public void given__server_branch_rev_userkey_different_clone_url__when__build__t assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://www.bitbucket.test/web")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@web.bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://web.bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -629,18 +713,20 @@ public void given__server_branch_norev_anon__when__build__then__scmBuilt() throw assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -674,18 +760,20 @@ public void given__server_branch_norev_userpass__when__build__then__scmBuilt() t assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -719,18 +807,20 @@ public void given__server_branch_norev_userkey__when__build__then__scmBuilt() th assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -764,19 +854,21 @@ public void given__server_branch_norev_userkey_different_clone_url__when__build_ assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://www.bitbucket.test/web")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@www.bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://www.bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/test-branch:refs/remotes/@{remote}/test-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -806,8 +898,8 @@ public void given__cloud_pullHead_rev_anon__when__build__then__scmBuilt() throws PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -816,22 +908,24 @@ public void given__cloud_pullHead_rev_anon__when__build__then__scmBuilt() throws assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); @@ -868,8 +962,8 @@ public void given__cloud_pullHead_rev_userpass__when__build__then__scmBuilt() th PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -878,22 +972,24 @@ public void given__cloud_pullHead_rev_userpass__when__build__then__scmBuilt() th assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); @@ -930,8 +1026,8 @@ public void given__cloud_pullHead_rev_userkey__when__build__then__scmBuilt() thr PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -940,33 +1036,34 @@ public void given__cloud_pullHead_rev_userkey__when__build__then__scmBuilt() thr assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); - assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + ), + List.of() + ); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/qa-branch:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/qa-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); @@ -992,8 +1089,8 @@ public void given__cloud_pullHead_rev_anon_sshtrait_anon__when__build__then__scm PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -1002,39 +1099,41 @@ public void given__cloud_pullHead_rev_anon_sshtrait_anon__when__build__then__scm assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); SSHCheckoutTrait sshTrait = new SSHCheckoutTrait(null); sshTrait.decorateBuilder(instance); GitSCM actual = instance.build(); assertThat(instance.credentialsId(), is(nullValue())); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/qa-branch:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(config.getCredentialsId(), is(nullValue())); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/qa-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); @@ -1060,8 +1159,8 @@ public void given__cloud_pullHead_rev_userpass_sshtrait_anon__when__build__then_ PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -1070,39 +1169,41 @@ public void given__cloud_pullHead_rev_userpass_sshtrait_anon__when__build__then_ assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); SSHCheckoutTrait sshTrait = new SSHCheckoutTrait(null); sshTrait.decorateBuilder(instance); GitSCM actual = instance.build(); assertThat(instance.credentialsId(), is(nullValue())); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/qa-branch:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(config.getCredentialsId(), is(nullValue())); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/qa-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); @@ -1128,8 +1229,8 @@ public void given__cloud_pullHead_rev_userkey_sshtrait_anon__when__build__then__ PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -1138,39 +1239,41 @@ public void given__cloud_pullHead_rev_userkey_sshtrait_anon__when__build__then__ assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + ), + List.of() + ); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); SSHCheckoutTrait sshTrait = new SSHCheckoutTrait(null); sshTrait.decorateBuilder(instance); GitSCM actual = instance.build(); assertThat(instance.credentialsId(), is(nullValue())); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/qa-branch:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(config.getCredentialsId(), is(nullValue())); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/qa-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); @@ -1196,8 +1299,8 @@ public void given__cloud_pullHead_rev_anon_sshtrait_userkey__when__build__then__ PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -1206,39 +1309,41 @@ public void given__cloud_pullHead_rev_anon_sshtrait_userkey__when__build__then__ assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); SSHCheckoutTrait sshTrait = new SSHCheckoutTrait("user-key"); sshTrait.decorateBuilder(instance); GitSCM actual = instance.build(); assertThat(instance.credentialsId(), is("user-key")); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/qa-branch:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/qa-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); @@ -1264,8 +1369,8 @@ public void given__cloud_pullHead_rev_userpass_sshtrait_userkey__when__build__th PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -1274,39 +1379,41 @@ public void given__cloud_pullHead_rev_userpass_sshtrait_userkey__when__build__th assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); SSHCheckoutTrait sshTrait = new SSHCheckoutTrait("user-key"); sshTrait.decorateBuilder(instance); GitSCM actual = instance.build(); assertThat(instance.credentialsId(), is("user-key")); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/qa-branch:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/qa-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); @@ -1332,8 +1439,8 @@ public void given__cloud_pullHead_rev_userkey_sshtrait_userkey__when__build__the PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -1342,39 +1449,41 @@ public void given__cloud_pullHead_rev_userkey_sshtrait_userkey__when__build__the assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + ), + List.of() + ); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); SSHCheckoutTrait sshTrait = new SSHCheckoutTrait("user-key"); sshTrait.decorateBuilder(instance); GitSCM actual = instance.build(); assertThat(instance.credentialsId(), is("user-key")); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/qa-branch:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/qa-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); @@ -1406,22 +1515,24 @@ public void given__cloud_pullHead_norev_anon__when__build__then__scmBuilt() thro assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); @@ -1452,22 +1563,24 @@ public void given__cloud_pullHead_norev_userpass__when__build__then__scmBuilt() assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); @@ -1498,33 +1611,35 @@ public void given__cloud_pullHead_norev_userkey__when__build__then__scmBuilt() t assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + ), + List.of() + ); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/qa-branch:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/qa-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); @@ -1539,8 +1654,8 @@ public void given__server_pullHead_rev_anon__when__build__then__scmBuilt() throw PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -1549,18 +1664,20 @@ public void given__server_pullHead_rev_anon__when__build__then__scmBuilt() throw assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -1596,35 +1713,39 @@ public void given__server_pullHead_rev_anon__when__build__then__scmBuilt() throw assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); } - @Test - public void given__server_pullHead_rev_userpass__when__build__then__scmBuilt() throws Exception { + public void given__server_withMirror_pullHead_rev_anon__when__build__then__scmBuilt() throws Exception { source.setServerUrl("https://bitbucket.test"); PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, - head, revision, "user-pass"); - assertThat(instance.credentialsId(), is("user-pass")); + head, revision, null); + assertThat(instance.credentialsId(), is(nullValue())); assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of( + new BitbucketHref("http", "https://bitbucket-mirror.test/scm/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket-mirror.test:7999/tester/test-repo.git") + ) + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -1635,7 +1756,7 @@ public void given__server_pullHead_rev_userpass__when__build__then__scmBuilt() t assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is("user-pass")); + assertThat(config.getCredentialsId(), is(nullValue())); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); @@ -1661,33 +1782,35 @@ public void given__server_pullHead_rev_userpass__when__build__then__scmBuilt() t } @Test - public void given__server_pullHead_rev_userkey__when__build__then__scmBuilt() throws Exception { + public void given__server_pullHead_defaultOrigin_rev_anon__when__build__then__scmBuilt() throws Exception { source.setServerUrl("https://bitbucket.test"); - PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", - new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), + PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "tester", "test-repo", "pr-branch", "1", "a fake title", + new BranchSCMHead("test-branch"), SCMHeadOrigin.DEFAULT, ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, - head, revision, "user-key"); - assertThat(instance.credentialsId(), is("user-key")); + head, revision, null); + assertThat(instance.credentialsId(), is(nullValue())); assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); - assertThat(instance.remote(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); + ), + List.of() + ); + assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/pr-branch:refs/remotes/@{remote}/pr-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -1696,16 +1819,16 @@ public void given__server_pullHead_rev_userkey__when__build__then__scmBuilt() th assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); - assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is("user-key")); + assertThat(config.getRefspec(), is("+refs/heads/pr-branch:refs/remotes/origin/pr-branch")); + assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(config.getCredentialsId(), is(nullValue())); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); - assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); - assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); + assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/pr-branch")); + assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/pr-branch")); assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); assertThat(actual.getExtensions(), containsInAnyOrder( @@ -1717,100 +1840,117 @@ public void given__server_pullHead_rev_userkey__when__build__then__scmBuilt() th AbstractGitSCMSource.SpecificRevisionBuildChooser revChooser = (AbstractGitSCMSource.SpecificRevisionBuildChooser) chooser.getBuildChooser(); Collection revisions = revChooser - .getCandidateRevisions(false, "qa-branch", Mockito.mock(GitClient.class), new LogTaskListener( + .getCandidateRevisions(false, "pr-branch", Mockito.mock(GitClient.class), new LogTaskListener( Logger.getAnonymousLogger(), Level.FINEST), null, null); assertThat(revisions, hasSize(1)); assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); } @Test - public void given__server_pullHead_rev_userkey_different_clone_url__when__build__then__scmBuilt() throws Exception { - source.setServerUrl("https://www.bitbucket.test/web"); - PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", - new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), + public void given__server_withMirror_pullHead_defaultOrigin_rev_anon__when__build__then__scmBuilt() throws Exception { + source.setServerUrl("https://bitbucket.test"); + PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "tester", "test-repo", "pr-branch", "1", "a fake title", + new BranchSCMHead("test-branch"), SCMHeadOrigin.DEFAULT, ChangeRequestCheckoutStrategy.HEAD); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, - head, revision, "user-key"); - assertThat(instance.credentialsId(), is("user-key")); - assertThat(instance.head(), is((SCMHead) head)); - assertThat(instance.revision(), is((SCMRevision) revision)); + head, revision, null); + assertThat(instance.credentialsId(), is(nullValue())); + assertThat(instance.head(), is(head)); + assertThat(instance.revision(), is(revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", - instance.remote(), is("https://www.bitbucket.test/web")); + instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); - assertThat(instance.browser().getRepoUrl(), - is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); + assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@www.bitbucket.test/scm/tester/test-repo.git"), - new BitbucketHref("ssh", "ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git") - )); - assertThat(instance.remote(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") + ), + List.of( + new BitbucketHref("http", "https://bitbucket-mirror.test/scm/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket-mirror.test:7999/tester/test-repo.git") + ) + ); + assertThat(instance.remote(), is("https://bitbucket-mirror.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/pr-branch:refs/remotes/@{remote}/pr-branch")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), - is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); - assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is("user-key")); + assertThat(config.getRefspec(), is("+refs/heads/pr-branch:refs/remotes/origin/pr-branch")); + assertThat(config.getUrl(), is("https://bitbucket-mirror.test/scm/tester/test-repo.git")); + assertThat(config.getCredentialsId(), is(nullValue())); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket-mirror.test/scm/tester/test-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); - assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); - assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); + assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/pr-branch")); + assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/pr-branch")); assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); assertThat(actual.getExtensions(), containsInAnyOrder( instanceOf(BuildChooserSetting.class), - instanceOf(GitSCMSourceDefaults.class)) - ); + instanceOf(GitSCMSourceDefaults.class), + instanceOf(FallbackToOtherRepositoryGitSCMExtension.class) + )); BuildChooserSetting chooser = getExtension(actual, BuildChooserSetting.class); assertThat(chooser.getBuildChooser(), instanceOf(AbstractGitSCMSource.SpecificRevisionBuildChooser.class)); AbstractGitSCMSource.SpecificRevisionBuildChooser revChooser = (AbstractGitSCMSource.SpecificRevisionBuildChooser) chooser.getBuildChooser(); Collection revisions = revChooser - .getCandidateRevisions(false, "qa-branch", Mockito.mock(GitClient.class), new LogTaskListener( + .getCandidateRevisions(false, "pr-branch", Mockito.mock(GitClient.class), new LogTaskListener( Logger.getAnonymousLogger(), Level.FINEST), null, null); assertThat(revisions, hasSize(1)); assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); } + @Test - public void given__server_pullHead_norev_anon__when__build__then__scmBuilt() throws Exception { + public void given__server_pullMerge_defaultOrigin_rev_anon__when__build__then__scmBuilt() throws Exception { source.setServerUrl("https://bitbucket.test"); - PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", - new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), - ChangeRequestCheckoutStrategy.HEAD); + PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "tester", "test-repo", "pr-branch", "1", "a fake title", + new BranchSCMHead("test-branch"), SCMHeadOrigin.DEFAULT, + ChangeRequestCheckoutStrategy.MERGE); + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + "deadbeefcafebabedeadbeefcafebabedeadbeef"), + new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, - head, null, null); + head, revision, null); assertThat(instance.credentialsId(), is(nullValue())); assertThat(instance.head(), is((SCMHead) head)); - assertThat(instance.revision(), is(nullValue())); + assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", - instance.remote(), is("https://bitbucket.test")); + instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat( + instance.refSpecs(), + contains( + "+refs/heads/pr-branch:refs/remotes/@{remote}/pr-branch", + "+refs/heads/test-branch:refs/remotes/@{remote}/test-branch" + ) + ); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -1819,14 +1959,356 @@ public void given__server_pullHead_norev_anon__when__build__then__scmBuilt() thr assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); - assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); + assertThat(config.getRefspec(), is("+refs/heads/pr-branch:refs/remotes/origin/pr-branch +refs/heads/test-branch:refs/remotes/origin/test-branch")); assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); assertThat(config.getCredentialsId(), is(nullValue())); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs(), hasSize(2)); + assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/pr-branch")); + assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/pr-branch")); + assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(origin.getFetchRefSpecs().get(1).getSource(), is("refs/heads/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).getDestination(), is("refs/remotes/origin/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(1).isWildcard(), is(false)); + assertThat(actual.getExtensions(), containsInAnyOrder( + instanceOf(BuildChooserSetting.class), + instanceOf(GitSCMSourceDefaults.class), + instanceOf(MergeWithGitSCMExtension.class) + )); + BuildChooserSetting chooser = getExtension(actual, BuildChooserSetting.class); + assertThat(chooser.getBuildChooser(), instanceOf(AbstractGitSCMSource.SpecificRevisionBuildChooser.class)); + AbstractGitSCMSource.SpecificRevisionBuildChooser revChooser = + (AbstractGitSCMSource.SpecificRevisionBuildChooser) chooser.getBuildChooser(); + Collection revisions = revChooser + .getCandidateRevisions(false, "pr-branch", Mockito.mock(GitClient.class), new LogTaskListener( + Logger.getAnonymousLogger(), Level.FINEST), null, null); + assertThat(revisions, hasSize(1)); + assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); + } + + @Test + public void given__server_withMirror_pullMerge_defaultOrigin_rev_anon__when__build__then__scmBuilt() throws Exception { + source.setServerUrl("https://bitbucket.test"); + PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "tester", "test-repo", "pr-branch", "1", "a fake title", + new BranchSCMHead("test-branch"), SCMHeadOrigin.DEFAULT, + ChangeRequestCheckoutStrategy.MERGE); + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + "deadbeefcafebabedeadbeefcafebabedeadbeef"), + new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); + BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, + head, revision, null); + assertThat(instance.credentialsId(), is(nullValue())); + assertThat(instance.head(), is((SCMHead) head)); + assertThat(instance.revision(), is((SCMRevision) revision)); + assertThat(instance.scmSource(), is(source)); + assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", + instance.remote(), is("https://bitbucket.test")); + assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); + assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); + + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") + ), + List.of( + new BitbucketHref("http", "https://bitbucket-mirror.test/scm/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket-mirror.test:7999/tester/test-repo.git") + ) + ); + assertThat(instance.remote(), is("https://bitbucket-mirror.test/scm/tester/test-repo.git")); + assertThat( + instance.refSpecs(), + contains( + "+refs/heads/pr-branch:refs/remotes/@{remote}/pr-branch", + "+refs/heads/test-branch:refs/remotes/@{remote}/test-branch" + ) + ); + + GitSCM actual = instance.build(); + assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); + assertThat(actual.getGitTool(), nullValue()); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); + UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); + assertThat(config.getName(), is("origin")); + assertThat(config.getRefspec(), is("+refs/heads/pr-branch:refs/remotes/origin/pr-branch +refs/heads/test-branch:refs/remotes/origin/test-branch")); + assertThat(config.getUrl(), is("https://bitbucket-mirror.test/scm/tester/test-repo.git")); + assertThat(config.getCredentialsId(), is(nullValue())); + RemoteConfig origin = actual.getRepositoryByName("origin"); + assertThat(origin, notNullValue()); + assertThat(origin.getURIs(), hasSize(1)); + assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket-mirror.test/scm/tester/test-repo.git")); + assertThat(origin.getFetchRefSpecs(), hasSize(2)); + assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/pr-branch")); + assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/pr-branch")); + assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(origin.getFetchRefSpecs().get(1).getSource(), is("refs/heads/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).getDestination(), is("refs/remotes/origin/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(1).isWildcard(), is(false)); + assertThat(actual.getExtensions(), containsInAnyOrder( + instanceOf(BuildChooserSetting.class), + instanceOf(GitSCMSourceDefaults.class), + instanceOf(MergeWithGitSCMExtension.class), + instanceOf(FallbackToOtherRepositoryGitSCMExtension.class) + )); + BuildChooserSetting chooser = getExtension(actual, BuildChooserSetting.class); + assertThat(chooser.getBuildChooser(), instanceOf(AbstractGitSCMSource.SpecificRevisionBuildChooser.class)); + AbstractGitSCMSource.SpecificRevisionBuildChooser revChooser = + (AbstractGitSCMSource.SpecificRevisionBuildChooser) chooser.getBuildChooser(); + Collection revisions = revChooser + .getCandidateRevisions(false, "pr-branch", Mockito.mock(GitClient.class), new LogTaskListener( + Logger.getAnonymousLogger(), Level.FINEST), null, null); + assertThat(revisions, hasSize(1)); + assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); + } + + @Test + public void given__server_pullHead_rev_userpass__when__build__then__scmBuilt() throws Exception { + source.setServerUrl("https://bitbucket.test"); + PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", + new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), + ChangeRequestCheckoutStrategy.HEAD); + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + "deadbeefcafebabedeadbeefcafebabedeadbeef"), + new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); + BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, + head, revision, "user-pass"); + assertThat(instance.credentialsId(), is("user-pass")); + assertThat(instance.head(), is((SCMHead) head)); + assertThat(instance.revision(), is((SCMRevision) revision)); + assertThat(instance.scmSource(), is(source)); + assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", + instance.remote(), is("https://bitbucket.test")); + assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); + assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); + + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") + ), + List.of() + ); + assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); + + GitSCM actual = instance.build(); + assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); + assertThat(actual.getGitTool(), nullValue()); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); + UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); + assertThat(config.getName(), is("origin")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); + assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(config.getCredentialsId(), is("user-pass")); + RemoteConfig origin = actual.getRepositoryByName("origin"); + assertThat(origin, notNullValue()); + assertThat(origin.getURIs(), hasSize(1)); + assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); + assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); + assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(actual.getExtensions(), containsInAnyOrder( + instanceOf(BuildChooserSetting.class), + instanceOf(GitSCMSourceDefaults.class)) + ); + BuildChooserSetting chooser = getExtension(actual, BuildChooserSetting.class); + assertThat(chooser.getBuildChooser(), instanceOf(AbstractGitSCMSource.SpecificRevisionBuildChooser.class)); + AbstractGitSCMSource.SpecificRevisionBuildChooser revChooser = + (AbstractGitSCMSource.SpecificRevisionBuildChooser) chooser.getBuildChooser(); + Collection revisions = revChooser + .getCandidateRevisions(false, "qa-branch", Mockito.mock(GitClient.class), new LogTaskListener( + Logger.getAnonymousLogger(), Level.FINEST), null, null); + assertThat(revisions, hasSize(1)); + assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); + } + + @Test + public void given__server_pullHead_rev_userkey__when__build__then__scmBuilt() throws Exception { + source.setServerUrl("https://bitbucket.test"); + PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", + new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), + ChangeRequestCheckoutStrategy.HEAD); + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + "deadbeefcafebabedeadbeefcafebabedeadbeef"), + new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); + BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, + head, revision, "user-key"); + assertThat(instance.credentialsId(), is("user-key")); + assertThat(instance.head(), is((SCMHead) head)); + assertThat(instance.revision(), is((SCMRevision) revision)); + assertThat(instance.scmSource(), is(source)); + assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", + instance.remote(), is("https://bitbucket.test")); + assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); + assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); + + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") + ), + List.of() + ); + assertThat(instance.remote(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); + + GitSCM actual = instance.build(); + assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); + assertThat(actual.getGitTool(), nullValue()); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); + UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); + assertThat(config.getName(), is("origin")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); + assertThat(config.getCredentialsId(), is("user-key")); + RemoteConfig origin = actual.getRepositoryByName("origin"); + assertThat(origin, notNullValue()); + assertThat(origin.getURIs(), hasSize(1)); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); + assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); + assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); + assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(actual.getExtensions(), containsInAnyOrder( + instanceOf(BuildChooserSetting.class), + instanceOf(GitSCMSourceDefaults.class)) + ); + BuildChooserSetting chooser = getExtension(actual, BuildChooserSetting.class); + assertThat(chooser.getBuildChooser(), instanceOf(AbstractGitSCMSource.SpecificRevisionBuildChooser.class)); + AbstractGitSCMSource.SpecificRevisionBuildChooser revChooser = + (AbstractGitSCMSource.SpecificRevisionBuildChooser) chooser.getBuildChooser(); + Collection revisions = revChooser + .getCandidateRevisions(false, "qa-branch", Mockito.mock(GitClient.class), new LogTaskListener( + Logger.getAnonymousLogger(), Level.FINEST), null, null); + assertThat(revisions, hasSize(1)); + assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); + } + + @Test + public void given__server_pullHead_rev_userkey_different_clone_url__when__build__then__scmBuilt() throws Exception { + source.setServerUrl("https://www.bitbucket.test/web"); + PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", + new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), + ChangeRequestCheckoutStrategy.HEAD); + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + "deadbeefcafebabedeadbeefcafebabedeadbeef"), + new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); + BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, + head, revision, "user-key"); + assertThat(instance.credentialsId(), is("user-key")); + assertThat(instance.head(), is((SCMHead) head)); + assertThat(instance.revision(), is((SCMRevision) revision)); + assertThat(instance.scmSource(), is(source)); + assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", + instance.remote(), is("https://www.bitbucket.test/web")); + assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); + assertThat(instance.browser().getRepoUrl(), + is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); + + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://www.bitbucket.test/scm/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git") + ), + List.of() + ); + assertThat(instance.remote(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); + + GitSCM actual = instance.build(); + assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); + assertThat(actual.getBrowser().getRepoUrl(), + is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); + assertThat(actual.getGitTool(), nullValue()); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); + UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); + assertThat(config.getName(), is("origin")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); + assertThat(config.getUrl(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); + assertThat(config.getCredentialsId(), is("user-key")); + RemoteConfig origin = actual.getRepositoryByName("origin"); + assertThat(origin, notNullValue()); + assertThat(origin.getURIs(), hasSize(1)); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); + assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); + assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); + assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(actual.getExtensions(), containsInAnyOrder( + instanceOf(BuildChooserSetting.class), + instanceOf(GitSCMSourceDefaults.class)) + ); + BuildChooserSetting chooser = getExtension(actual, BuildChooserSetting.class); + assertThat(chooser.getBuildChooser(), instanceOf(AbstractGitSCMSource.SpecificRevisionBuildChooser.class)); + AbstractGitSCMSource.SpecificRevisionBuildChooser revChooser = + (AbstractGitSCMSource.SpecificRevisionBuildChooser) chooser.getBuildChooser(); + Collection revisions = revChooser + .getCandidateRevisions(false, "qa-branch", Mockito.mock(GitClient.class), new LogTaskListener( + Logger.getAnonymousLogger(), Level.FINEST), null, null); + assertThat(revisions, hasSize(1)); + assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); + } + @Test + public void given__server_pullHead_norev_anon__when__build__then__scmBuilt() throws Exception { + source.setServerUrl("https://bitbucket.test"); + PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", + new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), + ChangeRequestCheckoutStrategy.HEAD); + BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, + head, null, null); + assertThat(instance.credentialsId(), is(nullValue())); + assertThat(instance.head(), is((SCMHead) head)); + assertThat(instance.revision(), is(nullValue())); + assertThat(instance.scmSource(), is(source)); + assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", + instance.remote(), is("https://bitbucket.test")); + assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); + assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); + + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") + ), + List.of() + ); + assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); + + GitSCM actual = instance.build(); + assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); + assertThat(actual.getGitTool(), nullValue()); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); + UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); + assertThat(config.getName(), is("origin")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); + assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(config.getCredentialsId(), is(nullValue())); + RemoteConfig origin = actual.getRepositoryByName("origin"); + assertThat(origin, notNullValue()); + assertThat(origin.getURIs(), hasSize(1)); + assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); @@ -1846,18 +2328,20 @@ public void given__server_pullHead_norev_userpass__when__build__then__scmBuilt() assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -1893,18 +2377,20 @@ public void given__server_pullHead_norev_userkey__when__build__then__scmBuilt() assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); @@ -1940,24 +2426,23 @@ public void given__server_pullHead_norev_userkey__when_different_clone_url__buil assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://www.bitbucket.test/web")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@www.bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://www.bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); - assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), - is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); @@ -1982,8 +2467,8 @@ public void given__cloud_pullMerge_rev_anon__when__build__then__scmBuilt() throw PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.MERGE); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -1992,22 +2477,24 @@ public void given__cloud_pullMerge_rev_anon__when__build__then__scmBuilt() throw assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(2)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); @@ -2064,8 +2551,8 @@ public void given__cloud_pullMerge_rev_userpass__when__build__then__scmBuilt() t PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.MERGE); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -2074,22 +2561,24 @@ public void given__cloud_pullMerge_rev_userpass__when__build__then__scmBuilt() t assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(2)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); @@ -2146,8 +2635,8 @@ public void given__cloud_pullMerge_rev_userkey__when__build__then__scmBuilt() th PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.MERGE); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -2156,38 +2645,40 @@ public void given__cloud_pullMerge_rev_userkey__when__build__then__scmBuilt() th assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + ), + List.of() + ); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(2)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/qa-branch:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); config = actual.getUserRemoteConfigs().get(1); assertThat(config.getName(), is("upstream")); assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/upstream/test-branch")); - assertThat(config.getUrl(), is("git@bitbucket.org:tester/test-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/tester/test-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/qa-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); @@ -2196,7 +2687,7 @@ public void given__cloud_pullMerge_rev_userkey__when__build__then__scmBuilt() th origin = actual.getRepositoryByName("upstream"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:tester/test-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/tester/test-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/upstream/test-branch")); @@ -2234,22 +2725,24 @@ public void given__cloud_pullMerge_norev_anon__when__build__then__scmBuilt() thr assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(2)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); @@ -2300,22 +2793,24 @@ public void given__cloud_pullMerge_norev_userpass__when__build__then__scmBuilt() assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(2)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); @@ -2366,38 +2861,40 @@ public void given__cloud_pullMerge_norev_userkey__when__build__then__scmBuilt() assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.org")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://bitbucket.org/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") - )); - assertThat(instance.remote(), is("git@bitbucket.org:qa/qa-repo.git")); + ), + List.of() + ); + assertThat(instance.remote(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); + assertThat(instance.refSpecs(), contains("+refs/heads/qa-branch:refs/remotes/@{remote}/PR-1")); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); - assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/qa/qa-repo")); + assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.org/tester/test-repo")); assertThat(actual.getGitTool(), nullValue()); assertThat(actual.getUserRemoteConfigs(), hasSize(2)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); assertThat(config.getRefspec(), is("+refs/heads/qa-branch:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); config = actual.getUserRemoteConfigs().get(1); assertThat(config.getName(), is("upstream")); assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/upstream/test-branch")); - assertThat(config.getUrl(), is("git@bitbucket.org:tester/test-repo.git")); + assertThat(config.getUrl(), is("ssh://git@bitbucket.org/tester/test-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:qa/qa-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/qa/qa-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/qa-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); @@ -2406,7 +2903,7 @@ public void given__cloud_pullMerge_norev_userkey__when__build__then__scmBuilt() origin = actual.getRepositoryByName("upstream"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("git@bitbucket.org:tester/test-repo.git")); + assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.org/tester/test-repo.git")); assertThat(origin.getFetchRefSpecs(), hasSize(1)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/upstream/test-branch")); @@ -2427,8 +2924,8 @@ public void given__server_pullMerge_rev_anon__when__build__then__scmBuilt() thro PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.MERGE); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -2437,52 +2934,50 @@ public void given__server_pullMerge_rev_anon__when__build__then__scmBuilt() thro assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat( + instance.refSpecs(), + contains( + "+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1", + "+refs/heads/test-branch:refs/remotes/@{remote}/test-branch" + ) + ); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); assertThat(actual.getGitTool(), nullValue()); - assertThat(actual.getUserRemoteConfigs(), hasSize(2)); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); - assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is(nullValue())); - config = actual.getUserRemoteConfigs().get(1); - assertThat(config.getName(), is("upstream")); - assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/upstream/test-branch")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1 +refs/heads/test-branch:refs/remotes/origin/test-branch")); assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is(nullValue())); + assertThat(config.getCredentialsId(), nullValue()); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs(), hasSize(2)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); - origin = actual.getRepositoryByName("upstream"); - assertThat(origin, notNullValue()); - assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); - assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/upstream/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); - assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(origin.getFetchRefSpecs().get(1).getSource(), is("refs/heads/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).getDestination(), is("refs/remotes/origin/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(1).isWildcard(), is(false)); assertThat(actual.getExtensions(), containsInAnyOrder( instanceOf(MergeWithGitSCMExtension.class), instanceOf(BuildChooserSetting.class), @@ -2500,7 +2995,7 @@ public void given__server_pullMerge_rev_anon__when__build__then__scmBuilt() thro assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); MergeWithGitSCMExtension merge = getExtension(actual, MergeWithGitSCMExtension.class); assertThat(merge, notNullValue()); - assertThat(merge.getBaseName(), is("remotes/upstream/test-branch")); + assertThat(merge.getBaseName(), is("remotes/origin/test-branch")); assertThat(merge.getBaseHash(), is("deadbeefcafebabedeadbeefcafebabedeadbeef")); } @@ -2511,8 +3006,8 @@ public void given__server_pullMerge_rev_userpass__when__build__then__scmBuilt() PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.MERGE); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -2521,52 +3016,50 @@ public void given__server_pullMerge_rev_userpass__when__build__then__scmBuilt() assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat( + instance.refSpecs(), + contains( + "+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1", + "+refs/heads/test-branch:refs/remotes/@{remote}/test-branch" + ) + ); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); assertThat(actual.getGitTool(), nullValue()); - assertThat(actual.getUserRemoteConfigs(), hasSize(2)); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); - assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is("user-pass")); - config = actual.getUserRemoteConfigs().get(1); - assertThat(config.getName(), is("upstream")); - assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/upstream/test-branch")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1 +refs/heads/test-branch:refs/remotes/origin/test-branch")); assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); assertThat(config.getCredentialsId(), is("user-pass")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs(), hasSize(2)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); - origin = actual.getRepositoryByName("upstream"); - assertThat(origin, notNullValue()); - assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); - assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/upstream/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); - assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(origin.getFetchRefSpecs().get(1).getSource(), is("refs/heads/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).getDestination(), is("refs/remotes/origin/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(1).isWildcard(), is(false)); assertThat(actual.getExtensions(), containsInAnyOrder( instanceOf(MergeWithGitSCMExtension.class), instanceOf(BuildChooserSetting.class), @@ -2584,7 +3077,7 @@ public void given__server_pullMerge_rev_userpass__when__build__then__scmBuilt() assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); MergeWithGitSCMExtension merge = getExtension(actual, MergeWithGitSCMExtension.class); assertThat(merge, notNullValue()); - assertThat(merge.getBaseName(), is("remotes/upstream/test-branch")); + assertThat(merge.getBaseName(), is("remotes/origin/test-branch")); assertThat(merge.getBaseHash(), is("deadbeefcafebabedeadbeefcafebabedeadbeef")); } @@ -2594,8 +3087,8 @@ public void given__server_pullMerge_rev_userkey__when__build__then__scmBuilt() t PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.MERGE); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -2604,52 +3097,50 @@ public void given__server_pullMerge_rev_userkey__when__build__then__scmBuilt() t assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); + assertThat( + instance.refSpecs(), + contains( + "+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1", + "+refs/heads/test-branch:refs/remotes/@{remote}/test-branch" + ) + ); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); assertThat(actual.getGitTool(), nullValue()); - assertThat(actual.getUserRemoteConfigs(), hasSize(2)); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); - assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is("user-key")); - config = actual.getUserRemoteConfigs().get(1); - assertThat(config.getName(), is("upstream")); - assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/upstream/test-branch")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1 +refs/heads/test-branch:refs/remotes/origin/test-branch")); assertThat(config.getUrl(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs(), hasSize(2)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); - origin = actual.getRepositoryByName("upstream"); - assertThat(origin, notNullValue()); - assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); - assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/upstream/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); - assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(origin.getFetchRefSpecs().get(1).getSource(), is("refs/heads/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).getDestination(), is("refs/remotes/origin/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(1).isWildcard(), is(false)); assertThat(actual.getExtensions(), containsInAnyOrder( instanceOf(MergeWithGitSCMExtension.class), instanceOf(BuildChooserSetting.class), @@ -2667,7 +3158,7 @@ public void given__server_pullMerge_rev_userkey__when__build__then__scmBuilt() t assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); MergeWithGitSCMExtension merge = getExtension(actual, MergeWithGitSCMExtension.class); assertThat(merge, notNullValue()); - assertThat(merge.getBaseName(), is("remotes/upstream/test-branch")); + assertThat(merge.getBaseName(), is("remotes/origin/test-branch")); assertThat(merge.getBaseHash(), is("deadbeefcafebabedeadbeefcafebabedeadbeef")); } @@ -2677,8 +3168,8 @@ public void given__server_pullMerge_rev_userkey__when_different_clone_url__build PullRequestSCMHead head = new PullRequestSCMHead("PR-1", "qa", "qa-repo", "qa-branch", "1", "a fake title", new BranchSCMHead("test-branch"), new SCMHeadOrigin.Fork("qa/qa-repo"), ChangeRequestCheckoutStrategy.MERGE); - PullRequestSCMRevision revision = - new PullRequestSCMRevision<>(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), + PullRequestSCMRevision revision = + new PullRequestSCMRevision(head, new AbstractGitSCMSource.SCMRevisionImpl(head.getTarget(), "deadbeefcafebabedeadbeefcafebabedeadbeef"), new AbstractGitSCMSource.SCMRevisionImpl(head, "cafebabedeadbeefcafebabedeadbeefcafebabe")); BitbucketGitSCMBuilder instance = new BitbucketGitSCMBuilder(source, @@ -2687,54 +3178,52 @@ public void given__server_pullMerge_rev_userkey__when_different_clone_url__build assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is((SCMRevision) revision)); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://www.bitbucket.test/web")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@www.bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://www.bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); + assertThat( + instance.refSpecs(), + contains( + "+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1", + "+refs/heads/test-branch:refs/remotes/@{remote}/test-branch" + ) + ); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); assertThat(actual.getBrowser().getRepoUrl(), is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); assertThat(actual.getGitTool(), nullValue()); - assertThat(actual.getUserRemoteConfigs(), hasSize(2)); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); - assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is("user-key")); - config = actual.getUserRemoteConfigs().get(1); - assertThat(config.getName(), is("upstream")); - assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/upstream/test-branch")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1 +refs/heads/test-branch:refs/remotes/origin/test-branch")); assertThat(config.getUrl(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); assertThat(origin.getURIs().get(0).toString(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs(), hasSize(2)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); - origin = actual.getRepositoryByName("upstream"); - assertThat(origin, notNullValue()); - assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); - assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/upstream/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); - assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(origin.getFetchRefSpecs().get(1).getSource(), is("refs/heads/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).getDestination(), is("refs/remotes/origin/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(1).isWildcard(), is(false)); assertThat(actual.getExtensions(), containsInAnyOrder( instanceOf(MergeWithGitSCMExtension.class), instanceOf(BuildChooserSetting.class), @@ -2752,7 +3241,7 @@ public void given__server_pullMerge_rev_userkey__when_different_clone_url__build assertThat(revisions.iterator().next().getSha1String(), is("cafebabedeadbeefcafebabedeadbeefcafebabe")); MergeWithGitSCMExtension merge = getExtension(actual, MergeWithGitSCMExtension.class); assertThat(merge, notNullValue()); - assertThat(merge.getBaseName(), is("remotes/upstream/test-branch")); + assertThat(merge.getBaseName(), is("remotes/origin/test-branch")); assertThat(merge.getBaseHash(), is("deadbeefcafebabedeadbeefcafebabedeadbeef")); } @@ -2768,59 +3257,57 @@ public void given__server_pullMerge_norev_anon__when__build__then__scmBuilt() th assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat( + instance.refSpecs(), + contains( + "+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1", + "+refs/heads/test-branch:refs/remotes/@{remote}/test-branch" + ) + ); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); assertThat(actual.getGitTool(), nullValue()); - assertThat(actual.getUserRemoteConfigs(), hasSize(2)); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); - assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is(nullValue())); - config = actual.getUserRemoteConfigs().get(1); - assertThat(config.getName(), is("upstream")); - assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/upstream/test-branch")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1 +refs/heads/test-branch:refs/remotes/origin/test-branch")); assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is(nullValue())); + assertThat(config.getCredentialsId(), nullValue()); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs(), hasSize(2)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); - origin = actual.getRepositoryByName("upstream"); - assertThat(origin, notNullValue()); - assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); - assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/upstream/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); - assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(origin.getFetchRefSpecs().get(1).getSource(), is("refs/heads/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).getDestination(), is("refs/remotes/origin/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(1).isWildcard(), is(false)); assertThat(actual.getExtensions(), containsInAnyOrder( instanceOf(MergeWithGitSCMExtension.class), instanceOf(GitSCMSourceDefaults.class)) ); MergeWithGitSCMExtension merge = getExtension(actual, MergeWithGitSCMExtension.class); assertThat(merge, notNullValue()); - assertThat(merge.getBaseName(), is("remotes/upstream/test-branch")); + assertThat(merge.getBaseName(), is("remotes/origin/test-branch")); assertThat(merge.getBaseHash(), is(nullValue())); } @@ -2836,59 +3323,57 @@ public void given__server_pullMerge_norev_userpass__when__build__then__scmBuilt( assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("https://bitbucket.test/scm/tester/test-repo.git")); + assertThat( + instance.refSpecs(), + contains( + "+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1", + "+refs/heads/test-branch:refs/remotes/@{remote}/test-branch" + ) + ); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); assertThat(actual.getGitTool(), nullValue()); - assertThat(actual.getUserRemoteConfigs(), hasSize(2)); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); - assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is("user-pass")); - config = actual.getUserRemoteConfigs().get(1); - assertThat(config.getName(), is("upstream")); - assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/upstream/test-branch")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1 +refs/heads/test-branch:refs/remotes/origin/test-branch")); assertThat(config.getUrl(), is("https://bitbucket.test/scm/tester/test-repo.git")); assertThat(config.getCredentialsId(), is("user-pass")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs(), hasSize(2)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); - origin = actual.getRepositoryByName("upstream"); - assertThat(origin, notNullValue()); - assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("https://bitbucket.test/scm/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); - assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/upstream/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); - assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(origin.getFetchRefSpecs().get(1).getSource(), is("refs/heads/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).getDestination(), is("refs/remotes/origin/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(1).isWildcard(), is(false)); assertThat(actual.getExtensions(), containsInAnyOrder( instanceOf(MergeWithGitSCMExtension.class), instanceOf(GitSCMSourceDefaults.class)) ); MergeWithGitSCMExtension merge = getExtension(actual, MergeWithGitSCMExtension.class); assertThat(merge, notNullValue()); - assertThat(merge.getBaseName(), is("remotes/upstream/test-branch")); + assertThat(merge.getBaseName(), is("remotes/origin/test-branch")); assertThat(merge.getBaseHash(), is(nullValue())); } @@ -2904,59 +3389,57 @@ public void given__server_pullMerge_norev_userkey__when__build__then__scmBuilt() assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://bitbucket.test")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); + assertThat( + instance.refSpecs(), + contains( + "+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1", + "+refs/heads/test-branch:refs/remotes/@{remote}/test-branch" + ) + ); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); assertThat(actual.getBrowser().getRepoUrl(), is("https://bitbucket.test/projects/tester/repos/test-repo")); assertThat(actual.getGitTool(), nullValue()); - assertThat(actual.getUserRemoteConfigs(), hasSize(2)); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); - assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is("user-key")); - config = actual.getUserRemoteConfigs().get(1); - assertThat(config.getName(), is("upstream")); - assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/upstream/test-branch")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1 +refs/heads/test-branch:refs/remotes/origin/test-branch")); assertThat(config.getUrl(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs(), hasSize(2)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); - origin = actual.getRepositoryByName("upstream"); - assertThat(origin, notNullValue()); - assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("ssh://git@bitbucket.test:7999/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); - assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/upstream/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); - assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(origin.getFetchRefSpecs().get(1).getSource(), is("refs/heads/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).getDestination(), is("refs/remotes/origin/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(1).isWildcard(), is(false)); assertThat(actual.getExtensions(), containsInAnyOrder( instanceOf(MergeWithGitSCMExtension.class), instanceOf(GitSCMSourceDefaults.class)) ); MergeWithGitSCMExtension merge = getExtension(actual, MergeWithGitSCMExtension.class); assertThat(merge, notNullValue()); - assertThat(merge.getBaseName(), is("remotes/upstream/test-branch")); + assertThat(merge.getBaseName(), is("remotes/origin/test-branch")); assertThat(merge.getBaseHash(), is(nullValue())); } @@ -2972,61 +3455,59 @@ public void given__server_pullMerge_norev_userkey_different_clone_url__when__bui assertThat(instance.head(), is((SCMHead) head)); assertThat(instance.revision(), is(nullValue())); assertThat(instance.scmSource(), is(source)); - assertThat(instance.refSpecs(), contains("+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1")); - assertThat(instance.cloneLinks(), is(Collections.emptyList())); assertThat("expecting dummy value until clone links provided or withBitbucketRemote called", instance.remote(), is("https://www.bitbucket.test/web")); assertThat(instance.browser(), instanceOf(BitbucketWeb.class)); assertThat(instance.browser().getRepoUrl(), is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); - instance.withCloneLinks(Arrays.asList( - new BitbucketHref("https", "https://tester@www.bitbucket.test/scm/tester/test-repo.git"), + instance.withCloneLinks( + List.of( + new BitbucketHref("http", "https://www.bitbucket.test/scm/tester/test-repo.git"), new BitbucketHref("ssh", "ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git") - )); + ), + List.of() + ); assertThat(instance.remote(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); + assertThat( + instance.refSpecs(), + contains( + "+refs/pull-requests/1/from:refs/remotes/@{remote}/PR-1", + "+refs/heads/test-branch:refs/remotes/@{remote}/test-branch" + ) + ); GitSCM actual = instance.build(); assertThat(actual.getBrowser(), instanceOf(BitbucketWeb.class)); assertThat(actual.getBrowser().getRepoUrl(), is("https://www.bitbucket.test/web/projects/tester/repos/test-repo")); assertThat(actual.getGitTool(), nullValue()); - assertThat(actual.getUserRemoteConfigs(), hasSize(2)); + assertThat(actual.getUserRemoteConfigs(), hasSize(1)); UserRemoteConfig config = actual.getUserRemoteConfigs().get(0); assertThat(config.getName(), is("origin")); - assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1")); - assertThat(config.getUrl(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); - assertThat(config.getCredentialsId(), is("user-key")); - config = actual.getUserRemoteConfigs().get(1); - assertThat(config.getName(), is("upstream")); - assertThat(config.getRefspec(), is("+refs/heads/test-branch:refs/remotes/upstream/test-branch")); + assertThat(config.getRefspec(), is("+refs/pull-requests/1/from:refs/remotes/origin/PR-1 +refs/heads/test-branch:refs/remotes/origin/test-branch")); assertThat(config.getUrl(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); assertThat(config.getCredentialsId(), is("user-key")); RemoteConfig origin = actual.getRepositoryByName("origin"); assertThat(origin, notNullValue()); assertThat(origin.getURIs(), hasSize(1)); assertThat(origin.getURIs().get(0).toString(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); + assertThat(origin.getFetchRefSpecs(), hasSize(2)); assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/pull-requests/1/from")); assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/origin/PR-1")); assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); - origin = actual.getRepositoryByName("upstream"); - assertThat(origin, notNullValue()); - assertThat(origin.getURIs(), hasSize(1)); - assertThat(origin.getURIs().get(0).toString(), is("ssh://git@ssh.bitbucket.test:7999/tester/test-repo.git")); - assertThat(origin.getFetchRefSpecs(), hasSize(1)); - assertThat(origin.getFetchRefSpecs().get(0).getSource(), is("refs/heads/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).getDestination(), is("refs/remotes/upstream/test-branch")); - assertThat(origin.getFetchRefSpecs().get(0).isForceUpdate(), is(true)); - assertThat(origin.getFetchRefSpecs().get(0).isWildcard(), is(false)); + assertThat(origin.getFetchRefSpecs().get(1).getSource(), is("refs/heads/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).getDestination(), is("refs/remotes/origin/test-branch")); + assertThat(origin.getFetchRefSpecs().get(1).isForceUpdate(), is(true)); + assertThat(origin.getFetchRefSpecs().get(1).isWildcard(), is(false)); assertThat(actual.getExtensions(), containsInAnyOrder( instanceOf(MergeWithGitSCMExtension.class), instanceOf(GitSCMSourceDefaults.class)) ); MergeWithGitSCMExtension merge = getExtension(actual, MergeWithGitSCMExtension.class); assertThat(merge, notNullValue()); - assertThat(merge.getBaseName(), is("remotes/upstream/test-branch")); + assertThat(merge.getBaseName(), is("remotes/origin/test-branch")); assertThat(merge.getBaseHash(), is(nullValue())); } diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMRevisionTest.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMRevisionTest.java index d855f3c5d..28f0672c2 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMRevisionTest.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMRevisionTest.java @@ -99,8 +99,8 @@ public void verify_revision_informations_are_valued() throws Exception { assertRevision(revision); } else if (head instanceof PullRequestSCMHead) { @SuppressWarnings("unchecked") - PullRequestSCMRevision revision = (PullRequestSCMRevision) source.retrieve(head, listener); - assertRevision(revision.getPull()); + PullRequestSCMRevision revision = (PullRequestSCMRevision) source.retrieve(head, listener); + assertRevision((BitbucketGitSCMRevision) revision.getPull()); assertRevision((BitbucketGitSCMRevision) revision.getTarget()); } else if(head instanceof TagSCMHead) { BitbucketTagSCMRevision revision = (BitbucketTagSCMRevision) source.retrieve(head, listener); diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BranchScanningTest.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BranchScanningTest.java index 07825c055..749c32bf4 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BranchScanningTest.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BranchScanningTest.java @@ -23,6 +23,7 @@ */ package com.cloudbees.jenkins.plugins.bitbucket; +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketHref; import com.cloudbees.jenkins.plugins.bitbucket.client.BitbucketCloudApiClient; import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketCloudEndpoint; import edu.umd.cs.findbugs.annotations.NonNull; @@ -42,7 +43,6 @@ import jenkins.scm.api.SCMSourceCriteria; import jenkins.scm.api.SCMSourceOwner; import jenkins.scm.api.mixin.ChangeRequestCheckoutStrategy; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; @@ -74,18 +74,18 @@ public void clearMockFactory() { public void uriResolverTest() throws Exception { // When there is no checkout credentials set, https must be resolved - assertThat(new BitbucketGitSCMBuilder(getBitbucketSCMSourceMock(false), - new BranchSCMHead("branch1"), null, - null).withBitbucketRemote().remote(), is("https://bitbucket.org/amuniz/test-repos.git")); - } - - @Test - public void remoteConfigsTest() throws Exception { - BitbucketSCMSource source = getBitbucketSCMSourceMock(false); - BitbucketGitSCMBuilder builder = - new BitbucketGitSCMBuilder(source, new BranchSCMHead("branch1"), null, - null); - assertThat(builder.refSpecs(), Matchers.contains("+refs/heads/branch1:refs/remotes/@{remote}/branch1")); + BitbucketGitSCMBuilder builder = new BitbucketGitSCMBuilder( + getBitbucketSCMSourceMock(false), + new BranchSCMHead("branch1"), null, + null + ).withCloneLinks( + List.of( + new BitbucketHref("http", "https://bitbucket.org/amuniz/test-repos.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket.org/amuniz/test-repo.git") + ), + List.of() + ); + assertThat(builder.remote(), is("https://bitbucket.org/amuniz/test-repos.git")); } @Test diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/UriResolverTest.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/UriResolverTest.java deleted file mode 100644 index e9db9d561..000000000 --- a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/UriResolverTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2016, CloudBees, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.cloudbees.jenkins.plugins.bitbucket; - -import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApi; -import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketAuthenticator; -import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryProtocol; -import com.cloudbees.jenkins.plugins.bitbucket.client.BitbucketCloudApiClient; -import com.cloudbees.jenkins.plugins.bitbucket.server.BitbucketServerWebhookImplementation; -import com.cloudbees.jenkins.plugins.bitbucket.server.client.BitbucketServerAPIClient; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class UriResolverTest { - - @Test - public void httpUriResolver() throws Exception { - BitbucketApi api = new BitbucketCloudApiClient(false, 0, 0, "test", null, null, (BitbucketAuthenticator) null); - assertEquals("https://bitbucket.org/user1/repo1.git", api.getRepositoryUri( - BitbucketRepositoryProtocol.HTTP, - null, - "user1", - "repo1" - )); - api = new BitbucketServerAPIClient("http://localhost:1234", "test", null, null, false, - BitbucketServerWebhookImplementation.PLUGIN); - assertEquals("http://localhost:1234/scm/user2/repo2.git", api.getRepositoryUri( - BitbucketRepositoryProtocol.HTTP, - null, - "user2", - "repo2" - )); - api = new BitbucketServerAPIClient("http://192.168.1.100:1234", "test", null, null, false, - BitbucketServerWebhookImplementation.PLUGIN); - assertEquals("http://192.168.1.100:1234/scm/user2/repo2.git", api.getRepositoryUri( - BitbucketRepositoryProtocol.HTTP, - null, - "user2", - "repo2" - )); - api = new BitbucketServerAPIClient("http://devtools.test:1234/git/web/", "test", null, null, false, - BitbucketServerWebhookImplementation.PLUGIN); - assertEquals("http://devtools.test:1234/git/web/scm/user2/repo2.git", api.getRepositoryUri( - BitbucketRepositoryProtocol.HTTP, - null, - "user2", - "repo2" - )); - } - - @Test - public void sshUriResolver() throws Exception { - BitbucketApi api = new BitbucketCloudApiClient(false, 0, 0, "test", null, null, (BitbucketAuthenticator) null); - assertEquals("git@bitbucket.org:user1/repo1.git", api.getRepositoryUri( - BitbucketRepositoryProtocol.SSH, - null, - "user1", - "repo1" - )); - api = new BitbucketServerAPIClient("http://localhost:1234", "test", null, null, false, - BitbucketServerWebhookImplementation.PLUGIN); - assertEquals("ssh://git@localhost:7999/user2/repo2.git", api.getRepositoryUri( - BitbucketRepositoryProtocol.SSH, - "ssh://git@localhost:7999/user1/repo1.git", - "user2", - "repo2" - )); - api = new BitbucketServerAPIClient("http://myserver", "test", null, null, false, - BitbucketServerWebhookImplementation.PLUGIN); - assertEquals("ssh://git@myserver:7999/user2/repo2.git", api.getRepositoryUri( - BitbucketRepositoryProtocol.SSH, - "ssh://git@myserver:7999/user1/repo1.git", - "user2", - "repo2" - )); - } - -} diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketEndpointConfigurationTest.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketEndpointConfigurationTest.java index 2683c7340..3f606543f 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketEndpointConfigurationTest.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketEndpointConfigurationTest.java @@ -650,7 +650,7 @@ public void should_support_configuration_as_code() throws Exception { BitbucketEndpointConfiguration instance = BitbucketEndpointConfiguration.get(); - assertThat(instance.getEndpoints(), hasSize(11)); + assertThat(instance.getEndpoints(), hasSize(12)); BitbucketCloudEndpoint endpoint1 = (BitbucketCloudEndpoint) instance.getEndpoints().get(0); assertThat(endpoint1.getDisplayName(), is(Messages.BitbucketCloudEndpoint_displayName())); @@ -740,7 +740,7 @@ public void should_support_configuration_as_code() throws Exception { assertThat(serverEndpoint.isCallCanMerge(), is(false)); assertThat(serverEndpoint.isCallChanges(), is(true)); assertThat(serverEndpoint.getWebhookImplementation(), is(BitbucketServerWebhookImplementation.PLUGIN)); - assertThat(serverEndpoint.getServerVersion(), is(BitbucketServerVersion.VERSION_6)); + assertThat(serverEndpoint.getServerVersion(), is(BitbucketServerVersion.VERSION_6_5)); serverEndpoint = (BitbucketServerEndpoint) instance.getEndpoints().get(9); assertThat(serverEndpoint.getDisplayName(), is("Example Inc")); @@ -750,7 +750,7 @@ public void should_support_configuration_as_code() throws Exception { assertThat(serverEndpoint.isCallCanMerge(), is(false)); assertThat(serverEndpoint.isCallChanges(), is(true)); assertThat(serverEndpoint.getWebhookImplementation(), is(BitbucketServerWebhookImplementation.PLUGIN)); - assertThat(serverEndpoint.getServerVersion(), is(BitbucketServerVersion.VERSION_5_10)); + assertThat(serverEndpoint.getServerVersion(), is(BitbucketServerVersion.VERSION_6)); serverEndpoint = (BitbucketServerEndpoint) instance.getEndpoints().get(10); assertThat(serverEndpoint.getDisplayName(), is("Example Inc")); @@ -760,6 +760,16 @@ public void should_support_configuration_as_code() throws Exception { assertThat(serverEndpoint.isCallCanMerge(), is(false)); assertThat(serverEndpoint.isCallChanges(), is(true)); assertThat(serverEndpoint.getWebhookImplementation(), is(BitbucketServerWebhookImplementation.PLUGIN)); + assertThat(serverEndpoint.getServerVersion(), is(BitbucketServerVersion.VERSION_5_10)); + + serverEndpoint = (BitbucketServerEndpoint) instance.getEndpoints().get(11); + assertThat(serverEndpoint.getDisplayName(), is("Example Inc")); + assertThat(serverEndpoint.getServerUrl(), is("http://bitbucket.example.com:8091")); + assertThat(serverEndpoint.isManageHooks(), is(false)); + assertThat(serverEndpoint.getCredentialsId(), is(nullValue())); + assertThat(serverEndpoint.isCallCanMerge(), is(false)); + assertThat(serverEndpoint.isCallChanges(), is(true)); + assertThat(serverEndpoint.getWebhookImplementation(), is(BitbucketServerWebhookImplementation.PLUGIN)); assertThat(serverEndpoint.getServerVersion(), is(BitbucketServerVersion.VERSION_5)); } diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfigurationTest.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfigurationTest.java index 2d48fe018..5ab3fd3f8 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfigurationTest.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfigurationTest.java @@ -36,6 +36,19 @@ public void given_instanceWithServerVersion6_when_getHooks_SERVER_PR_RVWR_UPDATE assertTrue(hook.getEvents().contains(HookEventType.SERVER_PULL_REQUEST_REVIEWER_UPDATED.getKey())); } + @Test + public void given_instanceWithServerVersion6_5_when_getHooks_SERVER_MIRROR_REPO_SYNC_EVENT_exists() { + WebhookConfiguration whc = new WebhookConfiguration(); + BitbucketSCMSource owner = Mockito.mock(BitbucketSCMSource.class); + final String server = "http://bitbucket.example.com:8091"; + when(owner.getServerUrl()).thenReturn(server); + when(owner.getEndpointJenkinsRootUrl()).thenReturn(server); + when(owner.getEndpointJenkinsRootUrl()).thenReturn(server); + when(owner.getMirrorId()).thenReturn("dummy-mirror-id"); + BitbucketWebHook hook = whc.getHook(owner); + assertTrue(hook.getEvents().contains(HookEventType.SERVER_MIRROR_REPO_SYNCHRONIZED.getKey())); + } + @Test public void given_instanceWithServerVersion510_when_getHooks_SERVER_PR_RVWR_UPDATE_EVENT_exists() { WebhookConfiguration whc = new WebhookConfiguration(); diff --git a/src/test/java/integration/ScanningFailuresTest.java b/src/test/java/integration/ScanningFailuresTest.java index e0817960c..fe90d9412 100644 --- a/src/test/java/integration/ScanningFailuresTest.java +++ b/src/test/java/integration/ScanningFailuresTest.java @@ -8,8 +8,8 @@ import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApi; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketBranch; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketCommit; +import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketHref; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepository; -import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryProtocol; import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketCloudEndpoint; import hudson.model.Result; import hudson.model.TopLevelItem; @@ -18,6 +18,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; @@ -44,14 +45,20 @@ import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @Issue("JENKINS-36029") public class ScanningFailuresTest { + private static final Map> REPOSITORY_LINKS = Map.of( + "clone", + List.of( + new BitbucketHref("http", "https://bitbucket.org/tester/test-repo.git"), + new BitbucketHref("ssh", "ssh://git@bitbucket.org/tester/test-repo.git") + ) + ); + @ClassRule public static JenkinsRule j = new JenkinsRule(); private static final Random entropy = new Random(); @@ -114,14 +121,12 @@ private void getBranchesFails(Callable exception, Result expectedResu when(api.checkPathExists(Mockito.anyString(), eq("Jenkinsfile"))).thenReturn(true); - when(api.getRepositoryUri(any(BitbucketRepositoryProtocol.class), - anyString(), eq("bob"), eq("foo"))).thenReturn(sampleRepo.fileUrl()); - BitbucketRepository repository = Mockito.mock(BitbucketRepository.class); when(api.getRepository()).thenReturn(repository); when(repository.getOwnerName()).thenReturn("bob"); when(repository.getRepositoryName()).thenReturn("foo"); when(repository.getScm()).thenReturn("git"); + when(repository.getLinks()).thenReturn(REPOSITORY_LINKS); BitbucketMockApiFactory.add(BitbucketCloudEndpoint.SERVER_URL, api); WorkflowMultiBranchProject mp = j.jenkins.createProject(WorkflowMultiBranchProject.class, "smokes"); @@ -184,14 +189,12 @@ public void checkPathExistsFails() throws Exception { when(api.checkPathExists(Mockito.anyString(), eq("Jenkinsfile"))).thenReturn(true); - when(api.getRepositoryUri(any(BitbucketRepositoryProtocol.class), - anyString(), eq("bob"), eq("foo"))).thenReturn(sampleRepo.fileUrl()); - BitbucketRepository repository = Mockito.mock(BitbucketRepository.class); when(api.getRepository()).thenReturn(repository); when(repository.getOwnerName()).thenReturn("bob"); when(repository.getRepositoryName()).thenReturn("foo"); when(repository.getScm()).thenReturn("git"); + when(repository.getLinks()).thenReturn(REPOSITORY_LINKS); BitbucketMockApiFactory.add(BitbucketCloudEndpoint.SERVER_URL, api); WorkflowMultiBranchProject mp = j.jenkins.createProject(WorkflowMultiBranchProject.class, "smokes"); @@ -246,14 +249,12 @@ public void resolveCommitFails() throws Exception { when(api.checkPathExists(Mockito.anyString(), eq("Jenkinsfile"))).thenReturn(true); - when(api.getRepositoryUri(any(BitbucketRepositoryProtocol.class), - anyString(), eq("bob"), eq("foo"))).thenReturn(sampleRepo.fileUrl()); - BitbucketRepository repository = Mockito.mock(BitbucketRepository.class); when(api.getRepository()).thenReturn(repository); when(repository.getOwnerName()).thenReturn("bob"); when(repository.getRepositoryName()).thenReturn("foo"); when(repository.getScm()).thenReturn("git"); + when(repository.getLinks()).thenReturn(REPOSITORY_LINKS); BitbucketMockApiFactory.add(BitbucketCloudEndpoint.SERVER_URL, api); WorkflowMultiBranchProject mp = j.jenkins.createProject(WorkflowMultiBranchProject.class, "smokes"); @@ -311,14 +312,12 @@ public void branchRemoved() throws Exception { when(api.checkPathExists(Mockito.anyString(), eq("Jenkinsfile"))).thenReturn(true); - when(api.getRepositoryUri(any(BitbucketRepositoryProtocol.class), - anyString(), eq("bob"), eq("foo"))).thenReturn(sampleRepo.fileUrl()); - BitbucketRepository repository = Mockito.mock(BitbucketRepository.class); when(api.getRepository()).thenReturn(repository); when(repository.getOwnerName()).thenReturn("bob"); when(repository.getRepositoryName()).thenReturn("foo"); when(repository.getScm()).thenReturn("git"); + when(repository.getLinks()).thenReturn(REPOSITORY_LINKS); BitbucketMockApiFactory.add(BitbucketCloudEndpoint.SERVER_URL, api); WorkflowMultiBranchProject mp = j.jenkins.createProject(WorkflowMultiBranchProject.class, "smokes"); diff --git a/src/test/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketEndpointConfigurationTest/configuration-as-code.yml b/src/test/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketEndpointConfigurationTest/configuration-as-code.yml index 1c7a91a62..eb40274cb 100644 --- a/src/test/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketEndpointConfigurationTest/configuration-as-code.yml +++ b/src/test/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketEndpointConfigurationTest/configuration-as-code.yml @@ -57,16 +57,22 @@ unclassified: serverUrl: "http://bitbucket.example.com:8088" callCanMerge: false callChanges: true - serverVersion: VERSION_6 + serverVersion: VERSION_6_5 - bitbucketServerEndpoint: displayName: "Example Inc" serverUrl: "http://bitbucket.example.com:8089" callCanMerge: false callChanges: true - serverVersion: VERSION_5_10 + serverVersion: VERSION_6 - bitbucketServerEndpoint: displayName: "Example Inc" serverUrl: "http://bitbucket.example.com:8090" callCanMerge: false callChanges: true + serverVersion: VERSION_5_10 + - bitbucketServerEndpoint: + displayName: "Example Inc" + serverUrl: "http://bitbucket.example.com:8091" + callCanMerge: false + callChanges: true serverVersion: VERSION_5 diff --git a/src/test/resources/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfigurationTest/configuration-as-code.yml b/src/test/resources/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfigurationTest/configuration-as-code.yml index 602dcfe20..4d9395bf2 100644 --- a/src/test/resources/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfigurationTest/configuration-as-code.yml +++ b/src/test/resources/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfigurationTest/configuration-as-code.yml @@ -9,6 +9,13 @@ unclassified: callChanges: false serverVersion: VERSION_7 webhookImplementation: NATIVE + - bitbucketServerEndpoint: + displayName: "Example Inc" + serverUrl: "http://bitbucket.example.com:8091" + callCanMerge: false + callChanges: true + serverVersion: VERSION_6_5 + webhookImplementation: NATIVE - bitbucketServerEndpoint: displayName: "Example Inc" serverUrl: "http://bitbucket.example.com:8088"