/******************************************************************************
* Copyright (c) 2011 GitHub Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Kevin Sawicki (GitHub Inc.) - initial API and implementation
*****************************************************************************/
package org.eclipse.mylyn.internal.github.core.pr;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.egit.github.core.Comment;
import org.eclipse.egit.github.core.IRepositoryIdProvider;
import org.eclipse.egit.github.core.PullRequest;
import org.eclipse.egit.github.core.RepositoryId;
import org.eclipse.egit.github.core.User;
import org.eclipse.egit.github.core.client.GitHubClient;
import org.eclipse.egit.github.core.client.GsonUtils;
import org.eclipse.egit.github.core.service.IssueService;
import org.eclipse.egit.github.core.service.PullRequestService;
import org.eclipse.mylyn.internal.github.core.GitHub;
import org.eclipse.mylyn.internal.github.core.GitHubTaskDataHandler;
import org.eclipse.mylyn.internal.github.core.issue.IssueConnector;
import org.eclipse.mylyn.tasks.core.ITaskMapping;
import org.eclipse.mylyn.tasks.core.RepositoryResponse;
import org.eclipse.mylyn.tasks.core.RepositoryResponse.ResponseKind;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskData;
/**
* GitHub issue task data handler
*/
public class PullRequestTaskDataHandler extends GitHubTaskDataHandler {
private static final String DATA_VERSION = "1.1"; //$NON-NLS-1$
/**
* Create GitHub issue task data handler for connector
*
* @param connector
*/
public PullRequestTaskDataHandler(PullRequestConnector connector) {
}
/**
* Create task data for pull request
*
* @param repository
* @param monitor
* @param repo
* @param prComp
* @return task data
*/
public TaskData createTaskData(TaskRepository repository,
IProgressMonitor monitor, IRepositoryIdProvider repo,
PullRequestComposite prComp) {
PullRequest pr = prComp.getRequest();
String key = Integer.toString(pr.getNumber());
TaskData data = new TaskData(getAttributeMapper(repository),
PullRequestConnector.KIND, repository.getRepositoryUrl(), key);
data.setVersion(DATA_VERSION);
createOperations(data, pr);
createAttribute(data, PullRequestAttribute.KEY.getMetadata(), key);
createAttribute(data, PullRequestAttribute.TITLE.getMetadata(),
pr.getTitle());
createAttribute(data, PullRequestAttribute.BODY.getMetadata(),
pr.getBody());
createAttribute(data, PullRequestAttribute.STATUS.getMetadata(),
pr.getState());
createAttribute(data, PullRequestAttribute.CREATION_DATE.getMetadata(),
pr.getCreatedAt());
createAttribute(data,
PullRequestAttribute.MODIFICATION_DATE.getMetadata(),
pr.getUpdatedAt());
createAttribute(data, PullRequestAttribute.CLOSED_DATE.getMetadata(),
pr.getClosedAt());
User reporter = pr.getUser();
createAttribute(data, PullRequestAttribute.REPORTER.getMetadata(),
reporter, repository);
String reporterGravatar = reporter != null ? reporter.getAvatarUrl()
: null;
createAttribute(data,
PullRequestAttribute.REPORTER_GRAVATAR.getMetadata(),
reporterGravatar);
createAttribute(data, PullRequestAttribute.COMMENT_NEW.getMetadata());
createAttribute(data, PullRequestAttribute.MODEL.getMetadata(),
GsonUtils.toJson(prComp));
return data;
}
private void createOperations(TaskData data, PullRequest pr) {
createOperationAttribute(data);
if (data.isNew())
return;
// Merged pull requests cannot be reopened
if (pr.isMerged())
return;
String state = pr.getState();
if (state != null) {
addOperation(data, pr, PullRequestOperation.LEAVE, true);
if (state.equals(IssueService.STATE_OPEN))
addOperation(data, pr, PullRequestOperation.CLOSE, false);
else if (state.equals(IssueService.STATE_CLOSED))
addOperation(data, pr, PullRequestOperation.REOPEN, false);
}
}
private void addOperation(TaskData data, PullRequest pr,
PullRequestOperation operation, boolean isDefault) {
String id = operation.getId();
String label = createOperationLabel(pr, operation);
addOperation(data, id, label, isDefault);
}
private String createOperationLabel(PullRequest pr,
PullRequestOperation operation) {
return operation == PullRequestOperation.LEAVE ? operation.getLabel()
+ pr.getState() : operation.getLabel();
}
/**
* Create task data for pull request
*
* @param repository
* @param monitor
* @param repo
* @param pr
* @param comments
* @return task data
*/
public TaskData createTaskData(TaskRepository repository,
IProgressMonitor monitor, IRepositoryIdProvider repo,
PullRequestComposite pr, List<Comment> comments) {
TaskData taskData = createTaskData(repository, monitor, repo, pr);
taskData.setPartial(false);
addComments(taskData.getRoot(), comments, repository);
return taskData;
}
private PullRequest createPullRequest(TaskData taskData) {
PullRequest pr = new PullRequest();
if (!taskData.isNew())
pr.setNumber(Integer.parseInt(taskData.getTaskId()));
pr.setBody(getAttributeValue(taskData,
PullRequestAttribute.BODY.getMetadata()));
pr.setTitle(getAttributeValue(taskData,
PullRequestAttribute.TITLE.getMetadata()));
return pr;
}
@Override
public boolean initializeTaskData(TaskRepository repository, TaskData data,
ITaskMapping initializationData, IProgressMonitor monitor)
throws CoreException {
data.setVersion(DATA_VERSION);
for (PullRequestAttribute attr : PullRequestAttribute.values())
if (attr.getMetadata().isInitTask())
createAttribute(data, attr.getMetadata(), (String) null);
return true;
}
@Override
public RepositoryResponse postTaskData(TaskRepository repository,
TaskData taskData, Set<TaskAttribute> oldAttributes,
IProgressMonitor monitor) throws CoreException {
String taskId = taskData.getTaskId();
PullRequest pr = createPullRequest(taskData);
RepositoryId repo = PullRequestConnector.getRepository(repository
.getRepositoryUrl());
try {
GitHubClient client = IssueConnector.createClient(repository);
boolean collaborator = isCollaborator(client, repo);
PullRequestService prService = new PullRequestService(client);
IssueService issueService = new IssueService(client);
if (taskData.isNew()) {
pr.setState(IssueService.STATE_OPEN);
pr = prService.createPullRequest(repo, pr);
taskId = Integer.toString(pr.getNumber());
} else {
// Handle new comment
String comment = getAttributeValue(taskData,
PullRequestAttribute.COMMENT_NEW.getMetadata());
if (comment != null && comment.length() > 0)
issueService.createComment(repo.getOwner(), repo.getName(),
taskId, comment);
boolean reporter = attributeMatchesUser(client,
PullRequestAttribute.REPORTER.getMetadata(), taskData);
if (collaborator || reporter) {
// Handle state change
TaskAttribute operationAttribute = taskData.getRoot()
.getAttribute(TaskAttribute.OPERATION);
if (operationAttribute != null) {
PullRequestOperation operation = PullRequestOperation
.fromId(operationAttribute.getValue());
if (operation == PullRequestOperation.REOPEN)
pr.setState(IssueService.STATE_OPEN);
else if (operation == PullRequestOperation.CLOSE)
pr.setState(IssueService.STATE_CLOSED);
}
prService.editPullRequest(repo, pr);
}
}
return new RepositoryResponse(
taskData.isNew() ? ResponseKind.TASK_CREATED
: ResponseKind.TASK_UPDATED, taskId);
} catch (IOException e) {
throw new CoreException(GitHub.createWrappedStatus(e));
}
}
}