|
23 | 23 | */
|
24 | 24 | package com.cloudbees.jenkins.plugins.bitbucket.server.client;
|
25 | 25 |
|
| 26 | +import com.cloudbees.jenkins.plugins.bitbucket.Messages; |
26 | 27 | import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApi;
|
27 | 28 | import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketAuthenticator;
|
28 | 29 | import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketBuildStatus;
|
|
87 | 88 | import jenkins.scm.api.SCMFile;
|
88 | 89 | import org.apache.commons.io.IOUtils;
|
89 | 90 | import org.apache.commons.lang.StringUtils;
|
| 91 | +import org.apache.http.Header; |
90 | 92 | import org.apache.http.HttpHost;
|
| 93 | +import org.apache.http.HttpResponse; |
91 | 94 | import org.apache.http.HttpStatus;
|
92 | 95 | import org.apache.http.client.methods.HttpGet;
|
| 96 | +import org.apache.http.client.methods.HttpPost; |
93 | 97 | import org.apache.http.conn.HttpClientConnectionManager;
|
| 98 | +import org.apache.http.entity.ContentType; |
| 99 | +import org.apache.http.entity.StringEntity; |
94 | 100 | import org.apache.http.impl.client.CloseableHttpClient;
|
95 | 101 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
96 | 102 | import org.apache.http.message.BasicNameValuePair;
|
@@ -509,7 +515,11 @@ public void postBuildStatus(@NonNull BitbucketBuildStatus status) throws IOExcep
|
509 | 515 | .set("repo", repositoryName)
|
510 | 516 | .set("hash", newStatus.getHash())
|
511 | 517 | .expand();
|
512 |
| - postRequest(url, JsonParser.toJson(newStatus)); |
| 518 | + |
| 519 | + HttpPost request = new HttpPost(url); |
| 520 | + request.setEntity(new StringEntity(JsonParser.toJson(newStatus), |
| 521 | + ContentType.create("application/json", "UTF-8"))); |
| 522 | + doRequest(request, true, this::adviceForBuildStatusError); |
513 | 523 | }
|
514 | 524 |
|
515 | 525 | /**
|
@@ -1051,4 +1061,45 @@ private Map<String,Object> collectLines(String response, final List<String> line
|
1051 | 1061 | return content;
|
1052 | 1062 | }
|
1053 | 1063 |
|
| 1064 | + // Gets user-visible advice for an HTTP error response when |
| 1065 | + // Bitbucket Server rejects a build status. |
| 1066 | + // Implements AbstractBitbucketApi.HttpErrorAdvisor#getAdvice. |
| 1067 | + @CheckForNull |
| 1068 | + private String adviceForBuildStatusError(HttpResponse response) { |
| 1069 | + // If the HTTP request failed because of an authorization |
| 1070 | + // problem, then make the exception message also show the |
| 1071 | + // Bitbucket user name with which Jenkins authenticated, |
| 1072 | + // the project name, and the repository name. |
| 1073 | + // |
| 1074 | + // Such an authorization problem can occur especially in a |
| 1075 | + // pull request from a personal fork: if Jenkins has been |
| 1076 | + // granted REPO_READ access on the target repository of the PR |
| 1077 | + // but no access on the fork, then it can read the PR |
| 1078 | + // information from the target repository and check out the |
| 1079 | + // files, but cannot post a build status to the fork. |
| 1080 | + // Showing the name of the fork will help the user or |
| 1081 | + // administrator grant the required access. |
| 1082 | + // |
| 1083 | + // If the HTTP request already includes valid credentials, |
| 1084 | + // but the Bitbucket user has not been granted access on the |
| 1085 | + // repository, then Bitbucket Server responds with HTTP status |
| 1086 | + // 401 (Unauthorized) and a WWW-Authenticate header field that |
| 1087 | + // requests OAuth, even though RFC 7235 section 2.1 recommends |
| 1088 | + // 403 (Forbidden). Let's recognize both 401 and 403. |
| 1089 | + int httpStatus = response.getStatusLine().getStatusCode(); |
| 1090 | + if (httpStatus == HttpStatus.SC_UNAUTHORIZED || httpStatus == HttpStatus.SC_FORBIDDEN) { |
| 1091 | + Header userNameHeader = response.getFirstHeader("X-AUSERNAME"); |
| 1092 | + if (userNameHeader != null |
| 1093 | + && !userNameHeader.getValue().equals("anonymous")) { |
| 1094 | + // Posting a build status requires REPO_READ access. |
| 1095 | + // https://docs.atlassian.com/bitbucket-server/rest/7.4.0/bitbucket-rest.html#idp219 |
| 1096 | + return Messages.BitbucketServerAPIClient_adviceForBuildStatusError( |
| 1097 | + userNameHeader.getValue(), |
| 1098 | + getUserCentricOwner(), |
| 1099 | + getRepositoryName()); |
| 1100 | + } |
| 1101 | + } |
| 1102 | + |
| 1103 | + return null; |
| 1104 | + } |
1054 | 1105 | }
|
0 commit comments