-
Notifications
You must be signed in to change notification settings - Fork 90
Improve Bitbucket support to sent back build statuses for pull requests #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,34 @@ | ||
package jetbrains.buildServer.commitPublisher.stash; | ||
|
||
import com.google.common.collect.Iterables; | ||
import com.google.gson.*; | ||
import com.intellij.openapi.diagnostic.Logger; | ||
import jetbrains.buildServer.commitPublisher.*; | ||
import jetbrains.buildServer.commitPublisher.stash.data.PullRequestInfo; | ||
import jetbrains.buildServer.commitPublisher.stash.data.StashCommit; | ||
import jetbrains.buildServer.serverSide.*; | ||
import jetbrains.buildServer.serverSide.executors.ExecutorServices; | ||
import jetbrains.buildServer.serverSide.impl.LogUtil; | ||
import jetbrains.buildServer.users.User; | ||
import org.apache.http.HttpEntity; | ||
import org.apache.http.HttpResponse; | ||
import org.apache.http.StatusLine; | ||
import org.apache.http.*; | ||
import org.apache.http.entity.ContentType; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
class StashPublisher extends HttpBasedCommitStatusPublisher { | ||
public static final String PUBLISH_QUEUED_BUILD_STATUS = "teamcity.stashCommitStatusPublisher.publishQueuedBuildStatus"; | ||
|
||
private static final Logger LOG = Logger.getInstance(StashPublisher.class.getName()); | ||
|
||
protected final Gson myGson = new Gson(); | ||
|
||
private final WebLinks myLinks; | ||
|
||
StashPublisher(@NotNull CommitStatusPublisherSettings settings, | ||
|
@@ -121,7 +127,16 @@ private void vote(@NotNull SBuild build, | |
@NotNull StashBuildStatus status, | ||
@NotNull String comment) { | ||
String msg = createMessage(status, build.getBuildPromotion().getBuildTypeExternalId(), getBuildName(build), myLinks.getViewResultsUrl(build), comment); | ||
vote(revision.getRevision(), msg, LogUtil.describe(build)); | ||
String commitRevision = revision.getRevision(); | ||
try { | ||
StashCommit commit = findPullRequestCommit(build); | ||
if (commit != null) { | ||
commitRevision = commit.id; | ||
} | ||
} catch (PublisherException e) { | ||
e.printStackTrace(); | ||
} | ||
vote(commitRevision, msg, LogUtil.describe(build)); | ||
} | ||
|
||
private void vote(@NotNull SQueuedBuild build, | ||
|
@@ -214,4 +229,58 @@ private String getUsername() { | |
private String getPassword() { | ||
return myParams.get(Constants.STASH_PASSWORD); | ||
} | ||
|
||
private StashCommit findPullRequestCommit(@NotNull SBuild build) throws PublisherException { | ||
String apiUrl = myParams.get(Constants.STASH_BASE_URL); | ||
String projectKey = myParams.get(Constants.STASH_PROJECT_KEY); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For other publishers, as well as for StashSettings::testConnection method we use GitRepositoryParser.parseRepository method to extract the repo details necessary to build the URL. It may be beneficial to introduce an explicit Commit Status Publisher settings for the same, but they have to be optional in my opinion. |
||
String repository = myParams.get(Constants.STASH_REPO_NAME); | ||
|
||
final List<StashCommit> lastCommit = new ArrayList<StashCommit>(); | ||
|
||
// Plugin will recognize pull request only when Branch specification parameter will be configured as below: | ||
// +:refs/pull-requests/(*/merge) | ||
// https://blog.jetbrains.com/teamcity/2013/02/automatically-building-pull-requests-from-github-with-teamcity | ||
|
||
if (build.getBranch().getName().contains("merge")) { // try to find pull request only for branches with merge in the name | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possible NPE: build.getBranch() is nullable |
||
String pullRequestNumber = build.getBranch().getName().replace("/merge",""); //remove merge from brache name to get only pull request number | ||
apiUrl = apiUrl + "/rest/api/1.0/projects/" + projectKey + "/repos/" + repository + "/pull-requests/" + pullRequestNumber + "/commits/"; | ||
LOG.debug("Bitbucket Pull Request apiUrl: " + apiUrl); | ||
} | ||
|
||
if (null != apiUrl || apiUrl.length() != 0) { | ||
try { | ||
HttpResponseProcessor processor = new DefaultHttpResponseProcessor() { | ||
@Override | ||
public void processResponse(HttpResponse response) throws HttpPublisherException, IOException { | ||
|
||
final HttpEntity entity = response.getEntity(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here and below please refer to the most recent changes in Commit Status Publisher, as the way we make and process these HTTP requests has changed a bit. |
||
if (null == entity) { | ||
throw new HttpPublisherException("Bitbucket publisher has received no response"); | ||
} | ||
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | ||
entity.writeTo(bos); | ||
final String json = bos.toString("utf-8"); | ||
PullRequestInfo commitInfo = myGson.fromJson(json, PullRequestInfo.class); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems if there is no PullRequestInfo in the response (e.g. the branch name contained "merge" substring for some other reason), the status publishing will fail. Is that right? |
||
if (null == commitInfo) | ||
throw new HttpPublisherException("Bitbucket Server publisher has received a malformed response"); | ||
if (null != commitInfo.values && !commitInfo.values.isEmpty()) { | ||
StashCommit commit = Iterables.get(commitInfo.values, 0); | ||
if (commit != null) { | ||
lastCommit.add(commit); | ||
} | ||
} | ||
} | ||
}; | ||
|
||
HttpHelper.get(apiUrl, getUsername(), getPassword(), | ||
Collections.singletonMap("Accept", "application/json"), BaseCommitStatusPublisher.DEFAULT_CONNECTION_TIMEOUT, processor); | ||
} catch (Exception ex) { | ||
throw new PublisherException(String.format("Bitbucket Server publisher has failed to connect to %s repository", apiUrl), ex); | ||
} | ||
} | ||
if (!lastCommit.isEmpty() && lastCommit.size() > 0) { | ||
return lastCommit.get(0); | ||
} | ||
return null; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package jetbrains.buildServer.commitPublisher.stash.data; | ||
|
||
import java.util.Collection; | ||
|
||
/** | ||
* Created by rafalkasa on 2017-03-19. | ||
*/ | ||
|
||
/** | ||
* This class does not represent full repository information | ||
*/ | ||
public class PullRequestInfo { | ||
public Collection<StashCommit> values; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package jetbrains.buildServer.commitPublisher.stash.data; | ||
|
||
/** | ||
* Created by rafalkasa on 2017-03-19. | ||
*/ | ||
|
||
/** | ||
* This class does not represent full repository information | ||
*/ | ||
public class StashCommit { | ||
public String id; | ||
public String displayId; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if this can be addressed easily, but at the moment we try to issue HTTP requests outside the threads where the event handlers code works, so the event handlers return as quick as possible. See postAsync(...) calls in vote(...). The findPullRequestCommit(...) call is performed in the same thread and will make buildStarted, buildFinished etc. waiting if the branch name contains "merge".