/****************************************************************************** * 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)); } } }