/****************************************************************************** * 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 org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; 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.Repository; import org.eclipse.egit.github.core.RepositoryId; import org.eclipse.egit.github.core.client.GitHubClient; import org.eclipse.egit.github.core.client.GsonUtils; import org.eclipse.egit.github.core.client.IGitHubConstants; import org.eclipse.egit.github.core.service.IssueService; import org.eclipse.egit.github.core.service.PullRequestService; import org.eclipse.mylyn.commons.net.AuthenticationCredentials; import org.eclipse.mylyn.commons.net.AuthenticationType; import org.eclipse.mylyn.internal.github.core.GitHub; import org.eclipse.mylyn.internal.github.core.QueryUtils; import org.eclipse.mylyn.internal.github.core.RepositoryConnector; import org.eclipse.mylyn.internal.github.core.issue.IssueConnector; import org.eclipse.mylyn.internal.tasks.core.IRepositoryConstants; import org.eclipse.mylyn.tasks.core.IRepositoryQuery; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler; import org.eclipse.mylyn.tasks.core.data.TaskData; import org.eclipse.mylyn.tasks.core.data.TaskDataCollector; import org.eclipse.mylyn.tasks.core.sync.ISynchronizationSession; /** * GitHub pull request connector. */ public class PullRequestConnector extends RepositoryConnector { /** * SEGMENT_PULL */ public static final String SEGMENT_PULL = "/pull"; //$NON-NLS-1$ /** * GitHub kind. */ public static final String KIND = "githubPullRequests"; //$NON-NLS-1$ /** * Get repository label for id provider. * * @param repo * @return label */ public static String getRepositoryLabel(IRepositoryIdProvider repo) { return repo.generateId() + Messages.PullRequestConnector_LabelPullRequests; } /** * Create pull request task repository * * @param repo * @param username * @param password * @return task repository */ public static TaskRepository createTaskRepository(Repository repo, String username, String password) { String url = PullRequestConnector.appendPulls(GitHub.createGitHubUrl( repo.getOwner().getLogin(), repo.getName())); TaskRepository repository = new TaskRepository(KIND, url); repository.setProperty(IRepositoryConstants.PROPERTY_LABEL, getRepositoryLabel(repo)); if (username != null && password != null) repository.setCredentials(AuthenticationType.REPOSITORY, new AuthenticationCredentials(username, password), true); repository.setProperty(IRepositoryConstants.PROPERTY_CATEGORY, IRepositoryConstants.CATEGORY_REVIEW); return repository; } /** * Appends a trailing '/pull's segment to the given url * * @param repoUrl * @return appended string */ public static String appendPulls(final String repoUrl) { return repoUrl + IGitHubConstants.SEGMENT_PULLS; } /** * Strip trailing '/pulls' segment from string if it ends with it. * * @param repoUrl * @return stripped string */ public static String stripPulls(String repoUrl) { if (repoUrl.endsWith(IGitHubConstants.SEGMENT_PULLS)) repoUrl = repoUrl.substring(0, repoUrl.length() - IGitHubConstants.SEGMENT_PULLS.length()); return repoUrl; } /** * Get pull request from task data * * @param data * @return pull request */ public static PullRequestComposite getPullRequest(TaskData data) { if (data == null) return null; String value = PullRequestAttribute.MODEL.getMetadata().getValue(data); if (value.length() == 0) return null; return GsonUtils.fromJson(value, PullRequestComposite.class); } /** * Get repository id from pull request task repository url * * @param prRepoUrl * @return repository id */ public static RepositoryId getRepository(String prRepoUrl) { return GitHub.getRepository(stripPulls(prRepoUrl)); } /** * GitHub specific {@link AbstractTaskDataHandler}. */ private final PullRequestTaskDataHandler taskDataHandler; /** * Create GitHub issue repository connector */ public PullRequestConnector() { taskDataHandler = new PullRequestTaskDataHandler(this); } /** * {@inheritDoc} * * @see #KIND */ @Override public String getConnectorKind() { return KIND; } /** * {@inheritDoc} */ @Override public String getLabel() { return Messages.PullRequestConnector_Label; } /** * {@inheritDoc} */ @Override public AbstractTaskDataHandler getTaskDataHandler() { return taskDataHandler; } @Override public IStatus performQuery(TaskRepository repository, IRepositoryQuery query, TaskDataCollector collector, ISynchronizationSession session, IProgressMonitor monitor) { IStatus result = Status.OK_STATUS; List<String> statuses = QueryUtils.getAttributes( IssueService.FILTER_STATE, query); monitor.beginTask(Messages.PullRequestConnector_TaskFetching, statuses.size()); try { RepositoryId repo = getRepository(repository.getRepositoryUrl()); GitHubClient client = IssueConnector.createClient(repository); PullRequestService service = new PullRequestService(client); IssueService commentService = new IssueService(client); for (String status : statuses) { List<PullRequest> pulls = service.getPullRequests(repo, status); // collect task data for (PullRequest pr : pulls) { pr = service.getPullRequest(repo, pr.getNumber()); PullRequestComposite prComp = new PullRequestComposite(); prComp.setRequest(pr); List<Comment> comments = null; if (pr.getComments() > 0) comments = commentService.getComments(repo.getOwner(), repo.getName(), Integer.toString(pr.getNumber())); if (pr.getCommits() > 0) prComp.setCommits(service.getCommits(repo, pr.getNumber())); TaskData taskData = taskDataHandler.createTaskData( repository, monitor, repo, prComp, comments); collector.accept(taskData); } monitor.worked(1); } } catch (IOException e) { result = GitHub.createWrappedStatus(e); } monitor.done(); return result; } @Override public TaskData getTaskData(TaskRepository repository, String taskId, IProgressMonitor monitor) throws CoreException { RepositoryId repo = getRepository(repository.getRepositoryUrl()); try { GitHubClient client = IssueConnector.createClient(repository); PullRequestService service = new PullRequestService(client); PullRequest pr = service.getPullRequest(repo, Integer.parseInt(taskId)); PullRequestComposite prComp = new PullRequestComposite(); prComp.setRequest(pr); IssueService commentService = new IssueService(client); List<Comment> comments = null; if (pr.getComments() > 0) comments = commentService.getComments(repo.getOwner(), repo.getName(), taskId); if (pr.getCommits() > 0) prComp.setCommits(service.getCommits(repo, pr.getNumber())); return taskDataHandler.createTaskData(repository, monitor, repo, prComp, comments); } catch (IOException e) { throw new CoreException(GitHub.createWrappedStatus(e)); } } @Override public String getRepositoryUrlFromTaskUrl(String taskFullUrl) { int lastPull = taskFullUrl.lastIndexOf(SEGMENT_PULL); if (lastPull != -1) return taskFullUrl.substring(0, lastPull) + IGitHubConstants.SEGMENT_PULLS; return null; } @Override public String getTaskUrl(String repositoryUrl, String taskId) { return stripPulls(repositoryUrl) + SEGMENT_PULL + "/" + taskId; //$NON-NLS-1$ } }