Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into bugfix/JENKINS-62780
Browse files Browse the repository at this point in the history
  • Loading branch information
bitwiseman committed Jul 17, 2020
2 parents 7cf4f69 + e35b6c9 commit f7b3a48
Show file tree
Hide file tree
Showing 23 changed files with 137 additions and 71 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ work
*.iml
*.iws
*.ipr

# VSCode
.factorypath
21 changes: 14 additions & 7 deletions docs/USER_GUIDE.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@

[IMPORTANT]
=====================================================================
On April 29th, 2019, link:https://developer.atlassian.com/cloud/bitbucket/bbc-gdpr-api-migration-guide/[Atlassian updated their suite APIs for both Bitbucket and JIRA] to comply with link:https://eugdpr.org[GDPR privacy requirements]. CloudBees has evaluated this change against the CloudBees BitBucket Branch Source plugin and the CloudBees JIRA plugin.
On March 5th, 2020, link:https://confluence.atlassian.com/bitbucketserver/bitbucket-server-7-0-release-notes-990546638.html[Atlassian releases Bitbucket Server 7] which removed some undocumented features with regards to pull requests.
. BitBucket Cloud Pipeline jobs created with "classic" Jenkins are unaffected.
. There is a limited impact to Bitbucket Cloud Pipeline jobs created using Blue Ocean:
.. If you are running Blue Ocean version 1.15.1 or earlier, you will be unable to create or edit BitBucket Cloud Pipeline jobs.
.. Upgrading to Blue Ocean 1.16.0 or later fixes this issue.
.. However, because "owner name" has been removed from the BitBucket REST API, when you edit Bitbucket Cloud Pipelines in the "classic" Jenkins UI, a UUID (instead of human-readable text) is displayed in the "owner" field of the Pipeline.
. BitBucket Server Pipeline jobs can no longer perform a lightweight checkout of the Jenkinsfile if you are using the merge strategy for builds.
.. BitBucket Server no longer stores the merged result of a PR to link:https://jira.atlassian.com/browse/BSERV-12284?focusedCommentId=2389584&[improve performance]
.. BitBucket Server Pipeline jobs will automatically fallback to heavyweight checkout
. BitBucket Server 7.x no longer automatically creates the required refs for pull requests
.. For Bitbucket Server Pipeline jobs to function for pull requests on BitBucket Server 7.x you need to enable "Call Changes api" option in the plugin configuration
We *do not* anticipate any broader user impact. If you encounter a change in behavior that you believe is due to the BitBucket or JIRA API changes, please link:https://support.cloudbees.com/hc/en-us[contact CloudBees Support] for assistance.
=====================================================================

[id=bitbucket-sect-intro]
Expand All @@ -23,6 +22,14 @@ as a multi-branch project source in two different ways:

IMPORTANT: This plugin is not compatible with versions of Bitbucket Server previous to 4.0.

[id=bitbucket-server-7]
== BitBucket Server 7 compatibility

_BitBucket Server 7.x_ is supported but does no longer support lightweight checkout for pull requests when merge strategy is used for build.

IMPORTANT: In order to have the pull request process working the "Call Changes api" option must be
enabled in _Manage Jenkins_ » _Configure System_

[id=bitbucket-scm-source]
== Branches and pull requests auto-discovering

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,8 +641,7 @@ class Skip extends IOException {
getPullRequestTitleCache()
.put(pull.getId(), StringUtils.defaultString(pull.getTitle()));
getPullRequestContributorCache().put(pull.getId(),
// TODO get more details on the author
new ContributorMetadataAction(pull.getAuthorLogin(), null, pull.getAuthorEmail()));
new ContributorMetadataAction(pull.getAuthorIdentifier(), pull.getAuthorLogin(), pull.getAuthorEmail()));
try {
// We store resolved hashes here so to avoid resolving the commits multiple times
for (final ChangeRequestCheckoutStrategy strategy : strategies.get(fork)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,19 @@ public interface BitbucketPullRequest {

String getLink();

/**
* Despite the name, this is a <em>display name</em> or <em>nickname</em> for the author, not a stable <em>username</em> for login.
*/
String getAuthorLogin();

/**
* Not set in Cloud.
*/
String getAuthorEmail();

/**
* Username or account identifier of the author.
*/
String getAuthorIdentifier();

List<BitbucketReviewer> getReviewers();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,22 @@ private void reconstructMissingData() {
BitbucketPullRequestValueRepository source = this.pullRequest.getSource();
if (source != null) {
BitbucketCloudRepository sourceRepository = source.getRepository();
if(sourceRepository != null) {
if (sourceRepository != null) {
if (sourceRepository.getScm() == null) {
sourceRepository.setScm(repository.getScm());
}
if (sourceRepository.getOwner() == null) {
if (sourceRepository.getOwnerName().equals(this.pullRequest.getAuthorLogin())) {
if (!sourceRepository.getOwnerName().equals(repository.getOwnerName())) { // i.e., a fork
BitbucketCloudRepositoryOwner owner = new BitbucketCloudRepositoryOwner();
owner.setUsername(this.pullRequest.getAuthorLogin());
owner.setDisplayName(this.pullRequest.getAuthorDisplayName());
if (this.repository.isPrivate()) {
sourceRepository.setPrivate(this.repository.isPrivate());
owner.setUsername(sourceRepository.getOwnerName());
owner.setDisplayName(this.pullRequest.getAuthorLogin());
if (repository.isPrivate()) {
sourceRepository.setPrivate(repository.isPrivate());
}
sourceRepository.setOwner(owner);
} else if (sourceRepository.getOwnerName().equals(this.repository.getOwnerName())) {
sourceRepository.setOwner(this.repository.getOwner());
sourceRepository.setPrivate(this.repository.isPrivate());
} else { // origin branch
sourceRepository.setOwner(repository.getOwner());
sourceRepository.setPrivate(repository.isPrivate());
}
}
}
Expand All @@ -95,7 +95,7 @@ private void reconstructMissingData() {
BitbucketCloudBranch sourceBranch = source.getBranch();
BitbucketCommit sourceCommit = source.getCommit();
if (sourceCommit != null
&& sourceBranch != null) {
&& sourceBranch != null) {
if (sourceBranch.getRawNode() == null) {
sourceBranch.setRawNode(source.getCommit().getHash());
}
Expand All @@ -106,23 +106,23 @@ private void reconstructMissingData() {
}
BitbucketPullRequestValueDestination destination = this.pullRequest.getDestination();
if (destination != null
&& destination.getRepository() != null) {
&& destination.getRepository() != null) {
if (destination.getRepository().getScm() == null) {
destination.getRepository().setScm(repository.getScm());
}
if (destination.getRepository().getOwner() == null
&& destination.getRepository().getOwnerName()
.equals(repository.getOwnerName())) {
&& destination.getRepository().getOwnerName()
.equals(repository.getOwnerName())) {
destination.getRepository().setOwner(repository.getOwner());
destination.getRepository().setPrivate(repository.isPrivate());
}
}
if (destination != null
&& destination.getCommit() != null
&& destination.getBranch() != null
&& destination.getBranch().getRawNode() == null) {
&& destination.getCommit() != null
&& destination.getBranch() != null
&& destination.getBranch().getRawNode() == null) {
destination.getBranch()
.setRawNode(destination.getCommit().getHash());
.setRawNode(destination.getCommit().getHash());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public String getLink() {

@Override
public String getAuthorLogin() {
return author.username;
return author.displayName;
}

@Override
Expand All @@ -107,10 +107,6 @@ public void setAuthor(Author author) {
this.author = author;
}

public String getAuthorDisplayName() {
return author.displayName;
}

@Override
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public List<BitbucketReviewer> getReviewers() {
Expand Down Expand Up @@ -155,27 +151,15 @@ public void setHref(String href) {
public static class Author {
@JsonProperty("account_id")
private String identifier;
private String username;
@JsonProperty("display_name")
@JsonProperty("nickname")
private String displayName;
public Author() {}
public Author(String username) {
this.username = username;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getIdentifier() {
return identifier;
}

public void setIndentifier(String identifier) {
public void setIdentifier(String identifier) {
this.identifier = identifier;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ public class BitbucketServerEndpoint extends AbstractBitbucketEndpoint {
*/
private boolean callCanMerge = true;

/**
* Whether to always call the can diff api when retrieving pull requests.
*/
private boolean callChanges = true;

/**
* @param displayName Optional name to use to describe the end-point.
* @param serverUrl The URL of this Bitbucket Server
Expand Down Expand Up @@ -128,6 +133,15 @@ public void setCallCanMerge(boolean callCanMerge) {
this.callCanMerge = callCanMerge;
}

public boolean isCallChanges() {
return callChanges;
}

@DataBoundSetter
public void setCallChanges(boolean callChanges) {
this.callChanges = callChanges;
}

/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ public SCMFileSystem build(@NonNull SCMSource source, @NonNull SCMHead head, @Ch
} else if (pr.getCheckoutStrategy() == ChangeRequestCheckoutStrategy.HEAD) {
ref = "pull-requests/" + pr.getId() + "/from";
} else if (pr.getCheckoutStrategy() == ChangeRequestCheckoutStrategy.MERGE) {
// No longer supported since bitbucket server v7, falls back to heavycheckout
ref = "pull-requests/" + pr.getId() + "/merge";
}
} else if (head instanceof BitbucketTagSCMHead) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ public enum HookEventType {
*/
SERVER_PULL_REQUEST_REVIEWER_UPDATED("pr:reviewer:updated", NativeServerPullRequestHookProcessor.class),

/**
* @see <a href="https://confluence.atlassian.com/bitbucketserver070/event-payload-996644369.html#Eventpayload-Sourcebranchupdated">Eventpayload-Sourcebranchupdated</a>
* @since Bitbucket Server 7.0
*/
SERVER_PULL_REQUEST_FROM_REF_UPDATED("pr:from_ref_updated", NativeServerPullRequestHookProcessor.class),

/**
* Sent when hitting the {@literal "Test connection"} button in Bitbucket Server. Apparently undocumented.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public void process(HookEventType hookEvent, String payload, BitbucketType insta
break;
case SERVER_PULL_REQUEST_MODIFIED:
case SERVER_PULL_REQUEST_REVIEWER_UPDATED:
case SERVER_PULL_REQUEST_FROM_REF_UPDATED:
eventType = SCMEvent.Type.UPDATED;
break;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public class WebhookConfiguration {
HookEventType.SERVER_PULL_REQUEST_DECLINED.getKey(),
HookEventType.SERVER_PULL_REQUEST_DELETED.getKey(),
HookEventType.SERVER_PULL_REQUEST_MODIFIED.getKey(),
HookEventType.SERVER_PULL_REQUEST_REVIEWER_UPDATED.getKey()
HookEventType.SERVER_PULL_REQUEST_REVIEWER_UPDATED.getKey(),
HookEventType.SERVER_PULL_REQUEST_FROM_REF_UPDATED.getKey()
));

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public class BitbucketServerAPIClient implements BitbucketApi {
private static final String API_PULL_REQUESTS_PATH = API_REPOSITORY_PATH + "/pull-requests{?start,limit,at,direction,state}";
private static final String API_PULL_REQUEST_PATH = API_REPOSITORY_PATH + "/pull-requests/{id}";
private static final String API_PULL_REQUEST_MERGE_PATH = API_REPOSITORY_PATH + "/pull-requests/{id}/merge";
private static final String API_PULL_REQUEST_CHANGES_PATH = API_REPOSITORY_PATH + "/pull-requests/{id}/changes{?start,limit}";
static final String API_BROWSE_PATH = API_REPOSITORY_PATH + "/browse{/path*}{?at}";
private static final String API_COMMITS_PATH = API_REPOSITORY_PATH + "/commits{/hash}";
private static final String API_PROJECT_PATH = API_BASE_PATH + "/projects/{owner}";
Expand Down Expand Up @@ -339,11 +340,21 @@ private List<BitbucketServerPullRequest> getPullRequests(UriTemplate template)
}

AbstractBitbucketEndpoint endpointConfig = BitbucketEndpointConfiguration.get().findEndpoint(baseURL);
if (endpointConfig instanceof BitbucketServerEndpoint && ((BitbucketServerEndpoint)endpointConfig).isCallCanMerge()) {
if (endpointConfig instanceof BitbucketServerEndpoint) {
final BitbucketServerEndpoint endpoint = (BitbucketServerEndpoint) endpointConfig;
if (!endpoint.isCallCanMerge() && !endpoint.isCallChanges()) {
return pullRequests;
}

// This is required for Bitbucket Server to update the refs/pull-requests/* references
// See https://community.atlassian.com/t5/Bitbucket-questions/Change-pull-request-refs-after-Commit-instead-of-after-Approval/qaq-p/194702#M6829
for (BitbucketServerPullRequest pullRequest : pullRequests) {
pullRequest.setCanMerge(getPullRequestCanMergeById(Integer.parseInt(pullRequest.getId())));
if (endpoint.isCallCanMerge()) {
pullRequest.setCanMerge(getPullRequestCanMergeById(pullRequest.getId()));
}
if (endpoint.isCallChanges()) {
callPullRequestChangesById(pullRequest.getId());
}
}
}

Expand Down Expand Up @@ -383,7 +394,17 @@ private void setupClosureForPRBranch(BitbucketServerPullRequest pr) {
}
}

private boolean getPullRequestCanMergeById(@NonNull Integer id) throws IOException {
private void callPullRequestChangesById(@NonNull String id) throws IOException {
String url = UriTemplate
.fromTemplate(API_PULL_REQUEST_CHANGES_PATH)
.set("owner", getUserCentricOwner())
.set("repo", repositoryName)
.set("id", id).set("limit", 1)
.expand();
getRequest(url);
}

private boolean getPullRequestCanMergeById(@NonNull String id) throws IOException {
String url = UriTemplate
.fromTemplate(API_PULL_REQUEST_MERGE_PATH)
.set("owner", getUserCentricOwner())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@
<f:entry field="callCanMerge">
<f:checkbox title="${%Call Can Merge}" default="true"/>
</f:entry>
<f:entry field="callChanges">
<f:checkbox title="${%Call Changes api}" default="true"/>
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Always call the can changes api on pull requests to ensure the source code references are up to date (since BitBucket Server v7).
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ private static BitbucketPullRequestValue getPullRequest() {
pr.setDestination(new BitbucketPullRequestValueDestination(repository, branch, commit));

pr.setId("23");
pr.setAuthor(new BitbucketPullRequestValue.Author("amuniz"));
pr.setAuthor(new BitbucketPullRequestValue.Author());
pr.setLinks(new BitbucketPullRequestValue.Links("https://bitbucket.org/amuniz/test-repos/pull-requests/23"));
return pr;
}
Expand Down
Loading

0 comments on commit f7b3a48

Please sign in to comment.