Skip to content

Commit 8b06426

Browse files
[JENKINS-71355] Avoid Fetching all branches and Tags to retrieve SCM … (#708)
* [JENKINS-71355] Avoid Fetching all branches and Tags to retrieve SCM Head * [JENKINS-71355] Adjust tests mocks * [JENKINS-71355] Retrieve commits from source/target branches for Bitbucket Cloud --------- Co-authored-by: Günter Grodotzki <[email protected]>
1 parent d9c5e84 commit 8b06426

16 files changed

+928
-48
lines changed

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

Lines changed: 105 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -819,59 +819,106 @@ private void retrieveTags(final BitbucketSCMSourceRequest request) throws IOExce
819819
protected SCMRevision retrieve(SCMHead head, TaskListener listener) throws IOException, InterruptedException {
820820
final BitbucketApi bitbucket = buildBitbucketClient();
821821
try {
822-
List<? extends BitbucketBranch> branches = bitbucket.getBranches();
823822
if (head instanceof PullRequestSCMHead) {
824823
PullRequestSCMHead h = (PullRequestSCMHead) head;
825-
BitbucketCommit targetRevision = findCommit(h.getTarget().getName(), branches, listener);
826-
if (targetRevision == null) {
827-
LOGGER.log(Level.WARNING, "No branch found in {0}/{1} with name [{2}]",
828-
new Object[]{repoOwner, repository, h.getTarget().getName()});
829-
return null;
830-
}
831824
BitbucketCommit sourceRevision;
825+
BitbucketCommit targetRevision;
826+
832827
if (bitbucket instanceof BitbucketCloudApiClient) {
833-
branches = head.getOrigin() == SCMHeadOrigin.DEFAULT
834-
? branches
835-
: buildBitbucketClient(h).getBranches();
836-
sourceRevision = findCommit(h.getBranchName(), branches, listener);
828+
// Bitbucket Cloud /pullrequests/{id} API endpoint only returns short commit IDs of the source
829+
// and target branch. We therefore retrieve the branches directly
830+
BitbucketBranch targetBranch = bitbucket.getBranch(h.getTarget().getName());
831+
832+
if(targetBranch == null) {
833+
listener.getLogger().format("No branch found in {0}/{1} with name [{2}]",
834+
repoOwner, repository, h.getTarget().getName());
835+
return null;
836+
}
837+
targetRevision = findCommit(targetBranch, listener);
838+
839+
if (targetRevision == null) {
840+
listener.getLogger().format("No branch found in {0}/{1} with name [{2}]",
841+
repoOwner, repository, h.getTarget().getName());
842+
return null;
843+
}
844+
845+
// Retrieve the source branch commit
846+
BitbucketBranch branch;
847+
if (head.getOrigin() == SCMHeadOrigin.DEFAULT) {
848+
branch = bitbucket.getBranch(h.getBranchName());
849+
} else {
850+
// In case of a forked branch, retrieve the branch as that owner
851+
branch = buildBitbucketClient(h).getBranch(h.getBranchName());
852+
}
853+
854+
if(branch == null) {
855+
listener.getLogger().format("No branch found in {0}/{1} with name [{2}]",
856+
repoOwner, repository, head.getName());
857+
return null;
858+
}
859+
860+
sourceRevision = findCommit(branch, listener);
861+
837862
} else {
863+
BitbucketPullRequest pr;
838864
try {
839-
BitbucketPullRequest pr = bitbucket.getPullRequestById(Integer.parseInt(h.getId()));
840-
sourceRevision = findPRCommit(pr, listener);
865+
pr = bitbucket.getPullRequestById(Integer.parseInt(h.getId()));
841866
} catch (NumberFormatException nfe) {
842867
LOGGER.log(Level.WARNING, "Cannot parse the PR id {0}", h.getId());
843-
sourceRevision = null;
868+
return null;
844869
}
870+
871+
targetRevision = findPRDestinationCommit(pr, listener);
872+
873+
if (targetRevision == null) {
874+
listener.getLogger().format("No branch found in {0}/{1} with name [{2}]",
875+
repoOwner, repository, h.getTarget().getName());
876+
return null;
877+
}
878+
879+
sourceRevision = findPRSourceCommit(pr, listener);
845880
}
881+
846882
if (sourceRevision == null) {
847-
LOGGER.log(Level.WARNING, "No revision found in {0}/{1} for PR-{2} [{3}]",
848-
new Object[]{
849-
h.getRepoOwner(),
850-
h.getRepository(),
851-
h.getId(),
852-
h.getBranchName()
853-
});
883+
listener.getLogger().format("No revision found in {0}/{1} for PR-{2} [{3}]",
884+
h.getRepoOwner(),
885+
h.getRepository(),
886+
h.getId(),
887+
h.getBranchName());
854888
return null;
855889
}
890+
856891
return new PullRequestSCMRevision<>(
857892
h,
858893
new BitbucketGitSCMRevision(h.getTarget(), targetRevision),
859894
new BitbucketGitSCMRevision(h, sourceRevision)
860895
);
861896
} else if (head instanceof BitbucketTagSCMHead) {
862897
BitbucketTagSCMHead tagHead = (BitbucketTagSCMHead) head;
863-
List<? extends BitbucketBranch> tags = bitbucket.getTags();
864-
BitbucketCommit revision = findCommit(head.getName(), tags, listener);
898+
BitbucketBranch tag = bitbucket.getTag(tagHead.getName());
899+
if(tag == null) {
900+
listener.getLogger().format( "No tag found in {0}/{1} with name [{2}]",
901+
repoOwner, repository, head.getName());
902+
return null;
903+
}
904+
BitbucketCommit revision = findCommit(tag, listener);
865905
if (revision == null) {
866-
LOGGER.log(Level.WARNING, "No tag found in {0}/{1} with name [{2}]", new Object[]{repoOwner, repository, head.getName()});
906+
listener.getLogger().format( "No revision found in {0}/{1} with name [{2}]",
907+
repoOwner, repository, head.getName());
867908
return null;
868909
}
869910
return new BitbucketTagSCMRevision(tagHead, revision);
870911
} else {
871-
BitbucketCommit revision = findCommit(head.getName(), branches, listener);
912+
BitbucketBranch branch = bitbucket.getBranch(head.getName());
913+
if(branch == null) {
914+
listener.getLogger().format("No branch found in {0}/{1} with name [{2}]",
915+
repoOwner, repository, head.getName());
916+
return null;
917+
}
918+
BitbucketCommit revision = findCommit(branch, listener);
872919
if (revision == null) {
873-
LOGGER.log(Level.WARNING, "No branch found in {0}/{1} with name [{2}]",
874-
new Object[]{repoOwner, repository, head.getName()});
920+
listener.getLogger().format("No revision found in {0}/{1} with name [{2}]",
921+
repoOwner, repository, head.getName());
875922
return null;
876923
}
877924
return new BitbucketGitSCMRevision(head, revision);
@@ -890,29 +937,23 @@ protected SCMRevision retrieve(SCMHead head, TaskListener listener) throws IOExc
890937
}
891938
}
892939

893-
private BitbucketCommit findCommit(@NonNull String branchName, List<? extends BitbucketBranch> branches, TaskListener listener) {
894-
for (final BitbucketBranch b : branches) {
895-
if (branchName.equals(b.getName())) {
896-
String revision = b.getRawNode();
897-
if (revision == null) {
898-
if (BitbucketCloudEndpoint.SERVER_URL.equals(getServerUrl())) {
899-
listener.getLogger().format("Cannot resolve the hash of the revision in branch %s%n",
900-
branchName);
901-
} else {
902-
listener.getLogger().format("Cannot resolve the hash of the revision in branch %s. "
903-
+ "Perhaps you are using Bitbucket Server previous to 4.x%n",
904-
branchName);
905-
}
906-
return null;
907-
}
908-
return new BranchHeadCommit(b);
940+
private BitbucketCommit findCommit(@NonNull BitbucketBranch branch, TaskListener listener) {
941+
String revision = branch.getRawNode();
942+
if (revision == null) {
943+
if (BitbucketCloudEndpoint.SERVER_URL.equals(getServerUrl())) {
944+
listener.getLogger().format("Cannot resolve the hash of the revision in branch %s%n",
945+
branch.getName());
946+
} else {
947+
listener.getLogger().format("Cannot resolve the hash of the revision in branch %s. "
948+
+ "Perhaps you are using Bitbucket Server previous to 4.x%n",
949+
branch.getName());
909950
}
951+
return null;
910952
}
911-
listener.getLogger().format("Cannot find the branch %s%n", branchName);
912-
return null;
953+
return new BranchHeadCommit(branch);
913954
}
914955

915-
private BitbucketCommit findPRCommit(BitbucketPullRequest pr, TaskListener listener) {
956+
private BitbucketCommit findPRSourceCommit(BitbucketPullRequest pr, TaskListener listener) {
916957
// if I use getCommit() the branch closure is trigger immediately
917958
BitbucketBranch branch = pr.getSource().getBranch();
918959
String hash = branch.getRawNode();
@@ -930,6 +971,24 @@ private BitbucketCommit findPRCommit(BitbucketPullRequest pr, TaskListener liste
930971
return new BranchHeadCommit(branch);
931972
}
932973

974+
private BitbucketCommit findPRDestinationCommit(BitbucketPullRequest pr, TaskListener listener) {
975+
// if I use getCommit() the branch closure is trigger immediately
976+
BitbucketBranch branch = pr.getDestination().getBranch();
977+
String hash = branch.getRawNode();
978+
if (hash == null) {
979+
if (BitbucketCloudEndpoint.SERVER_URL.equals(getServerUrl())) {
980+
listener.getLogger().format("Cannot resolve the hash of the revision in PR-%s%n",
981+
pr.getId());
982+
} else {
983+
listener.getLogger().format("Cannot resolve the hash of the revision in PR-%s. "
984+
+ "Perhaps you are using Bitbucket Server previous to 4.x%n",
985+
pr.getId());
986+
}
987+
return null;
988+
}
989+
return new BranchHeadCommit(branch);
990+
}
991+
933992
@Override
934993
public SCM build(SCMHead head, SCMRevision revision) {
935994
BitbucketRepositoryType type;

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ boolean checkPathExists(@NonNull String branchOrHash, @NonNull String path)
136136
@CheckForNull
137137
String getDefaultBranch() throws IOException, InterruptedException;
138138

139+
/**
140+
* Returns a branch in the repository.
141+
*
142+
* @return a branch in the repository.
143+
* @throws IOException if there was a network communications error.
144+
* @throws InterruptedException if interrupted while waiting on remote communications.
145+
*/
146+
@CheckForNull
147+
BitbucketBranch getBranch(@NonNull String branchName) throws IOException, InterruptedException;
148+
139149
/**
140150
* Returns the branches in the repository.
141151
*
@@ -146,6 +156,16 @@ boolean checkPathExists(@NonNull String branchOrHash, @NonNull String path)
146156
@NonNull
147157
List<? extends BitbucketBranch> getBranches() throws IOException, InterruptedException;
148158

159+
/**
160+
* Returns a tag in the repository.
161+
*
162+
* @return a tag in the repository.
163+
* @throws IOException if there was a network communications error.
164+
* @throws InterruptedException if interrupted while waiting on remote communications.
165+
*/
166+
@CheckForNull
167+
BitbucketBranch getTag(@NonNull String tagName) throws IOException, InterruptedException;
168+
149169
/**
150170
* Returns the tags in the repository.
151171
*

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,24 @@ public String getDefaultBranch() throws IOException, InterruptedException {
472472
return cachedDefaultBranch;
473473
}
474474

475+
/**
476+
* {@inheritDoc}
477+
*/
478+
@Override
479+
public BitbucketCloudBranch getTag(@NonNull String tagName) throws IOException, InterruptedException {
480+
String url = UriTemplate.fromTemplate(REPO_URL_TEMPLATE + "/refs/tags/{name}")
481+
.set("owner", owner)
482+
.set("repo", repositoryName)
483+
.set("name", tagName)
484+
.expand();
485+
String response = getRequest(url);
486+
try {
487+
return getSingleBranch(response);
488+
} catch (IOException e) {
489+
throw new IOException("I/O error when parsing response from URL: " + url, e);
490+
}
491+
}
492+
475493
/**
476494
* {@inheritDoc}
477495
*/
@@ -481,6 +499,24 @@ public List<BitbucketCloudBranch> getTags() throws IOException, InterruptedExcep
481499
return getBranchesByRef("/refs/tags");
482500
}
483501

502+
/**
503+
* {@inheritDoc}
504+
*/
505+
@Override
506+
public BitbucketCloudBranch getBranch(@NonNull String branchName) throws IOException, InterruptedException {
507+
String url = UriTemplate.fromTemplate(REPO_URL_TEMPLATE + "/refs/branches/{name}")
508+
.set("owner", owner)
509+
.set("repo", repositoryName)
510+
.set("name", branchName)
511+
.expand();
512+
String response = getRequest(url);
513+
try {
514+
return getSingleBranch(response);
515+
} catch (IOException e) {
516+
throw new IOException("I/O error when parsing response from URL: " + url, e);
517+
}
518+
}
519+
484520
/**
485521
* {@inheritDoc}
486522
*/
@@ -1065,6 +1101,10 @@ private List<BitbucketCloudBranch> getAllBranches(String response) throws IOExce
10651101
return activeBranches;
10661102
}
10671103

1104+
private BitbucketCloudBranch getSingleBranch(String response) throws IOException {
1105+
return JsonParser.mapper.readValue(response, new TypeReference<BitbucketCloudBranch>(){});
1106+
}
1107+
10681108
@Override
10691109
public Iterable<SCMFile> getDirectoryContent(final BitbucketSCMFile parent) throws IOException, InterruptedException {
10701110
String url = UriTemplate.fromTemplate(REPO_URL_TEMPLATE + "/src{/branchOrHash,path}")

0 commit comments

Comments
 (0)