/*******************************************************************************
* 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.egit.github.core.service;
import static org.eclipse.egit.github.core.client.IGitHubConstants.SEGMENT_COMMENTS;
import static org.eclipse.egit.github.core.client.IGitHubConstants.SEGMENT_COMMITS;
import static org.eclipse.egit.github.core.client.IGitHubConstants.SEGMENT_FILES;
import static org.eclipse.egit.github.core.client.IGitHubConstants.SEGMENT_MERGE;
import static org.eclipse.egit.github.core.client.IGitHubConstants.SEGMENT_PULLS;
import static org.eclipse.egit.github.core.client.IGitHubConstants.SEGMENT_REPOS;
import static org.eclipse.egit.github.core.client.PagedRequest.PAGE_FIRST;
import static org.eclipse.egit.github.core.client.PagedRequest.PAGE_SIZE;
import com.google.gson.reflect.TypeToken;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.egit.github.core.CommitComment;
import org.eclipse.egit.github.core.CommitFile;
import org.eclipse.egit.github.core.IRepositoryIdProvider;
import org.eclipse.egit.github.core.MergeStatus;
import org.eclipse.egit.github.core.PullRequest;
import org.eclipse.egit.github.core.PullRequestMarker;
import org.eclipse.egit.github.core.RepositoryCommit;
import org.eclipse.egit.github.core.client.GitHubClient;
import org.eclipse.egit.github.core.client.GitHubRequest;
import org.eclipse.egit.github.core.client.PageIterator;
import org.eclipse.egit.github.core.client.PagedRequest;
/**
* Service class for creating, updating, getting, and listing pull requests as
* well as getting the commits associated with a pull request and the files
* modified by a pull request.
*
* @see <a href="http://developer.github.com/v3/pulls">GitHub Pull Requests API
* documentation</a>
* @see <a href="http://developer.github.com/v3/pulls/comments">GitHub Pull
* Request comments API documentation</a>
*/
public class PullRequestService extends GitHubService {
/**
* PR_TITLE
*/
public static final String PR_TITLE = "title"; //$NON-NLS-1$
/**
* PR_BODY
*/
public static final String PR_BODY = "body"; //$NON-NLS-1$
/**
* PR_BASE
*/
public static final String PR_BASE = "base"; //$NON-NLS-1$
/**
* PR_HEAD
*/
public static final String PR_HEAD = "head"; //$NON-NLS-1$
/**
* PR_STATE
*/
public static final String PR_STATE = "state"; //$NON-NLS-1$
/**
* Create pull request service
*/
public PullRequestService() {
super();
}
/**
* Create pull request service
*
* @param client
*/
public PullRequestService(GitHubClient client) {
super(client);
}
/**
* Create request for single pull request
*
* @param repository
* @param id
* @return request
* @throws IOException
*/
public PullRequest getPullRequest(IRepositoryIdProvider repository, int id)
throws IOException {
final String repoId = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(repoId);
uri.append(SEGMENT_PULLS);
uri.append('/').append(id);
GitHubRequest request = createRequest();
request.setUri(uri);
request.setType(PullRequest.class);
return (PullRequest) client.get(request).getBody();
}
/**
* Create paged request for fetching pull requests
*
* @param provider
* @param state
* @param start
* @param size
* @return paged request
*/
protected PagedRequest<PullRequest> createPullsRequest(
IRepositoryIdProvider provider, String state, int start, int size) {
final String id = getId(provider);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(id);
uri.append(SEGMENT_PULLS);
PagedRequest<PullRequest> request = createPagedRequest(start, size);
request.setUri(uri);
if (state != null)
request.setParams(Collections.singletonMap(
IssueService.FILTER_STATE, state));
request.setType(new TypeToken<List<PullRequest>>() {
}.getType());
return request;
}
/**
* Get pull requests from repository matching state
*
* @param repository
* @param state
* @return list of pull requests
* @throws IOException
*/
public List<PullRequest> getPullRequests(IRepositoryIdProvider repository,
String state) throws IOException {
return getAll(pagePullRequests(repository, state));
}
/**
* Page pull requests with given state
*
* @param repository
* @param state
* @return iterator over pages of pull requests
*/
public PageIterator<PullRequest> pagePullRequests(
IRepositoryIdProvider repository, String state) {
return pagePullRequests(repository, state, PAGE_SIZE);
}
/**
* Page pull requests with given state
*
* @param repository
* @param state
* @param size
* @return iterator over pages of pull requests
*/
public PageIterator<PullRequest> pagePullRequests(
IRepositoryIdProvider repository, String state, int size) {
return pagePullRequests(repository, state, PAGE_FIRST, size);
}
/**
* Page pull requests with given state
*
* @param repository
* @param state
* @param start
* @param size
* @return iterator over pages of pull requests
*/
public PageIterator<PullRequest> pagePullRequests(
IRepositoryIdProvider repository, String state, int start, int size) {
PagedRequest<PullRequest> request = createPullsRequest(repository,
state, start, size);
return createPageIterator(request);
}
private Map<String, String> createPrMap(PullRequest request) {
Map<String, String> params = new HashMap<String, String>();
if (request != null) {
String title = request.getTitle();
if (title != null)
params.put(PR_TITLE, title);
String body = request.getBody();
if (body != null)
params.put(PR_BODY, body);
PullRequestMarker baseMarker = request.getBase();
if (baseMarker != null) {
String base = baseMarker.getLabel();
if (base != null)
params.put(PR_BASE, base);
}
PullRequestMarker headMarker = request.getHead();
if (headMarker != null) {
String head = headMarker.getLabel();
if (head != null)
params.put(PR_HEAD, head);
}
}
return params;
}
private Map<String, String> editPrMap(PullRequest request) {
Map<String, String> params = new HashMap<String, String>();
String title = request.getTitle();
if (title != null)
params.put(PR_TITLE, title);
String body = request.getBody();
if (body != null)
params.put(PR_BODY, body);
String state = request.getState();
if (state != null)
params.put(PR_STATE, state);
return params;
}
/**
* Create pull request
*
* @param repository
* @param request
* @return created pull request
* @throws IOException
*/
public PullRequest createPullRequest(IRepositoryIdProvider repository,
PullRequest request) throws IOException {
String id = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(id);
uri.append(SEGMENT_PULLS);
Map<String, String> params = createPrMap(request);
return client.post(uri.toString(), params, PullRequest.class);
}
/**
* Create pull request by attaching branch information to an existing issue
*
* @param repository
* @param issueId
* @param head
* @param base
* @return created pull request
* @throws IOException
*/
public PullRequest createPullRequest(IRepositoryIdProvider repository,
int issueId, String head, String base) throws IOException {
String id = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(id);
uri.append(SEGMENT_PULLS);
Map<String, Object> params = new HashMap<String, Object>();
params.put("issue", issueId); //$NON-NLS-1$
params.put("head", head); //$NON-NLS-1$
params.put("base", base); //$NON-NLS-1$
return client.post(uri.toString(), params, PullRequest.class);
}
/**
* Edit pull request
*
* @param repository
* @param request
* @return edited pull request
* @throws IOException
*/
public PullRequest editPullRequest(IRepositoryIdProvider repository,
PullRequest request) throws IOException {
String id = getId(repository);
if (request == null)
throw new IllegalArgumentException("Request cannot be null"); //$NON-NLS-1$
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(id);
uri.append(SEGMENT_PULLS);
uri.append('/').append(request.getNumber());
Map<String, String> params = editPrMap(request);
return client.post(uri.toString(), params, PullRequest.class);
}
/**
* Get all commits associated with given pull request id
*
* @param repository
* @param id
* @return list of commits
* @throws IOException
*/
public List<RepositoryCommit> getCommits(IRepositoryIdProvider repository,
int id) throws IOException {
final String repoId = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(repoId);
uri.append(SEGMENT_PULLS);
uri.append('/').append(id);
uri.append(SEGMENT_COMMITS);
PagedRequest<RepositoryCommit> request = createPagedRequest();
request.setUri(uri);
request.setType(new TypeToken<List<RepositoryCommit>>() {
}.getType());
return getAll(request);
}
/**
* Get all changed files associated with given pull request id
*
* @param repository
* @param id
* @return list of commit files
* @throws IOException
*/
public List<CommitFile> getFiles(IRepositoryIdProvider repository, int id)
throws IOException {
final String repoId = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(repoId);
uri.append(SEGMENT_PULLS);
uri.append('/').append(id);
uri.append(SEGMENT_FILES);
PagedRequest<CommitFile> request = createPagedRequest();
request.setUri(uri);
request.setType(new TypeToken<List<CommitFile>>() {
}.getType());
return getAll(request);
}
/**
* Is the given pull request id merged?
*
* @param repository
* @param id
* @return true if merge, false otherwise
* @throws IOException
*/
public boolean isMerged(IRepositoryIdProvider repository, int id)
throws IOException {
String repoId = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(repoId);
uri.append(SEGMENT_PULLS);
uri.append('/').append(id);
uri.append(SEGMENT_MERGE);
return check(uri.toString());
}
/**
* Merge given pull request
*
* @param repository
* @param id
* @param commitMessage
* @return status of merge
* @throws IOException
*/
public MergeStatus merge(IRepositoryIdProvider repository, int id,
String commitMessage) throws IOException {
String repoId = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(repoId);
uri.append(SEGMENT_PULLS);
uri.append('/').append(id);
uri.append(SEGMENT_MERGE);
return client.put(uri.toString(),
Collections.singletonMap("commit_message", commitMessage), //$NON-NLS-1$
MergeStatus.class);
}
/**
* Get all comments on commits in given pull request
*
* @param repository
* @param id
* @return non-null list of comments
* @throws IOException
*/
public List<CommitComment> getComments(IRepositoryIdProvider repository,
int id) throws IOException {
return getAll(pageComments(repository, id));
}
/**
* Page pull request commit comments
*
* @param repository
* @param id
* @return iterator over pages of commit comments
*/
public PageIterator<CommitComment> pageComments(
IRepositoryIdProvider repository, int id) {
return pageComments(repository, id, PAGE_SIZE);
}
/**
* Page pull request commit comments
*
* @param repository
* @param id
* @param size
* @return iterator over pages of commit comments
*/
public PageIterator<CommitComment> pageComments(
IRepositoryIdProvider repository, int id, int size) {
return pageComments(repository, id, PAGE_FIRST, size);
}
/**
* Page pull request commit comments
*
* @param repository
* @param id
* @param start
* @param size
* @return iterator over pages of commit comments
*/
public PageIterator<CommitComment> pageComments(
IRepositoryIdProvider repository, int id, int start, int size) {
String repoId = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(repoId);
uri.append(SEGMENT_PULLS);
uri.append('/').append(id);
uri.append(SEGMENT_COMMENTS);
PagedRequest<CommitComment> request = createPagedRequest(start, size);
request.setUri(uri);
request.setType(new TypeToken<List<CommitComment>>() {
}.getType());
return createPageIterator(request);
}
/**
* Get commit comment with given id
*
* @param repository
* @param commentId
* @return commit comment
* @throws IOException
*/
public CommitComment getComment(IRepositoryIdProvider repository,
long commentId) throws IOException {
String repoId = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(repoId);
uri.append(SEGMENT_PULLS);
uri.append(SEGMENT_COMMENTS);
uri.append('/').append(commentId);
GitHubRequest request = createRequest();
request.setUri(uri);
request.setType(CommitComment.class);
return (CommitComment) client.get(request).getBody();
}
/**
* Create comment on given pull request
*
* @param repository
* @param id
* @param comment
* @return created commit comment
* @throws IOException
*/
public CommitComment createComment(IRepositoryIdProvider repository,
int id, CommitComment comment) throws IOException {
String repoId = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(repoId);
uri.append(SEGMENT_PULLS);
uri.append('/').append(id);
uri.append(SEGMENT_COMMENTS);
return client.post(uri.toString(), comment, CommitComment.class);
}
/**
* Reply to given comment
*
* @param repository
* @param pullRequestId
* @param commentId
* @param body
* @return created comment
* @throws IOException
*/
public CommitComment replyToComment(IRepositoryIdProvider repository,
int pullRequestId, int commentId, String body) throws IOException {
String repoId = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(repoId);
uri.append(SEGMENT_PULLS);
uri.append('/').append(pullRequestId);
uri.append(SEGMENT_COMMENTS);
Map<String, String> params = new HashMap<String, String>();
params.put("in_reply_to", Integer.toString(commentId)); //$NON-NLS-1$
params.put("body", body); //$NON-NLS-1$
return client.post(uri.toString(), params, CommitComment.class);
}
/**
* Edit pull request comment
*
* @param repository
* @param comment
* @return edited comment
* @throws IOException
*/
public CommitComment editComment(IRepositoryIdProvider repository,
CommitComment comment) throws IOException {
String repoId = getId(repository);
if (comment == null)
throw new IllegalArgumentException("Comment cannot be null"); //$NON-NLS-1$
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(repoId);
uri.append(SEGMENT_PULLS);
uri.append(SEGMENT_COMMENTS);
uri.append('/').append(comment.getId());
return client.post(uri.toString(), comment, CommitComment.class);
}
/**
* Delete commit comment with given id
*
* @param repository
* @param commentId
* @throws IOException
*/
public void deleteComment(IRepositoryIdProvider repository, long commentId)
throws IOException {
String repoId = getId(repository);
StringBuilder uri = new StringBuilder(SEGMENT_REPOS);
uri.append('/').append(repoId);
uri.append(SEGMENT_PULLS);
uri.append(SEGMENT_COMMENTS);
uri.append('/').append(commentId);
client.delete(uri.toString());
}
}