| // Copyright (C) 2013 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| package com.googlesource.gerrit.plugins.github.wizard; |
| |
| import com.google.common.base.Optional; |
| import com.google.common.base.Strings; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Maps; |
| import com.google.gerrit.entities.Project.NameKey; |
| import com.google.gerrit.index.query.QueryParseException; |
| import com.google.gerrit.server.IdentifiedUser; |
| import com.google.gerrit.server.git.GitRepositoryManager; |
| import com.google.gerrit.server.project.ProjectCache; |
| import com.google.gerrit.server.query.change.ChangeQueryBuilder; |
| import com.google.gerrit.server.query.change.ChangeQueryProcessor; |
| import com.google.gson.JsonArray; |
| import com.google.gson.JsonObject; |
| import com.google.gson.JsonPrimitive; |
| import com.google.inject.Inject; |
| import com.google.inject.Provider; |
| import com.google.inject.Singleton; |
| import com.googlesource.gerrit.plugins.github.GitHubConfig; |
| import com.googlesource.gerrit.plugins.github.oauth.GitHubLogin; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.text.SimpleDateFormat; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| import org.eclipse.jgit.errors.IncorrectObjectTypeException; |
| import org.eclipse.jgit.lib.Repository; |
| import org.kohsuke.github.GHIssueState; |
| import org.kohsuke.github.GHPullRequest; |
| import org.kohsuke.github.GHPullRequestCommitDetail; |
| import org.kohsuke.github.GHRepository; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| @Singleton |
| public class PullRequestListController implements VelocityController { |
| private static final Logger LOG = LoggerFactory.getLogger(PullRequestListController.class); |
| private static final String DATE_FMT = "yyyy-MM-dd HH:mm z"; |
| |
| private final GitHubConfig config; |
| private final ProjectCache projectsCache; |
| private final GitRepositoryManager repoMgr; |
| private final Provider<ChangeQueryProcessor> qp; |
| private final ChangeQueryBuilder changeQuery; |
| |
| @Inject |
| public PullRequestListController( |
| ProjectCache projectsCache, |
| GitRepositoryManager repoMgr, |
| GitHubConfig config, |
| Provider<ChangeQueryProcessor> qp, |
| ChangeQueryBuilder changeQuery) { |
| this.projectsCache = projectsCache; |
| this.repoMgr = repoMgr; |
| this.config = config; |
| this.qp = qp; |
| this.changeQuery = changeQuery; |
| } |
| |
| @Override |
| public void doAction( |
| IdentifiedUser user, |
| GitHubLogin hubLogin, |
| HttpServletRequest req, |
| HttpServletResponse resp, |
| ControllerErrors errors) |
| throws ServletException, IOException { |
| try (PrintWriter out = resp.getWriter()) { |
| SimpleDateFormat dateFmt = new SimpleDateFormat(DATE_FMT); |
| String organisation = req.getParameter("organisation"); |
| String repository = req.getParameter("repository"); |
| Map<String, List<GHPullRequest>> pullRequests = |
| getPullRequests(hubLogin, organisation, repository); |
| |
| JsonArray reposPullRequests = new JsonArray(); |
| for (Entry<String, List<GHPullRequest>> repoEntry : pullRequests.entrySet()) { |
| JsonObject repoPullRequests = new JsonObject(); |
| |
| repoPullRequests.add("repository", new JsonPrimitive(repoEntry.getKey())); |
| |
| if (repoEntry.getValue() != null) { |
| JsonArray prArray = new JsonArray(); |
| for (GHPullRequest pr : repoEntry.getValue()) { |
| JsonObject prObj = new JsonObject(); |
| prObj.add("id", new JsonPrimitive(new Integer(pr.getNumber()))); |
| prObj.add("title", new JsonPrimitive(pr.getTitle())); |
| prObj.add("body", new JsonPrimitive(pr.getBody())); |
| prObj.add( |
| "author", new JsonPrimitive(pr.getUser() == null ? "" : pr.getUser().getLogin())); |
| prObj.add("status", new JsonPrimitive(pr.getState().name())); |
| prObj.add("date", new JsonPrimitive(dateFmt.format(pr.getUpdatedAt()))); |
| |
| prArray.add(prObj); |
| } |
| repoPullRequests.add("pullrequests", prArray); |
| } |
| |
| reposPullRequests.add(repoPullRequests); |
| } |
| out.println(reposPullRequests.toString()); |
| } |
| } |
| |
| private Map<String, List<GHPullRequest>> getPullRequests( |
| GitHubLogin hubLogin, String organisation, String repository) throws IOException { |
| return getPullRequests( |
| hubLogin, projectsCache.byName(organisation + "/" + Strings.nullToEmpty(repository))); |
| } |
| |
| private Map<String, List<GHPullRequest>> getPullRequests( |
| GitHubLogin login, Iterable<NameKey> repos) throws IOException { |
| int numPullRequests = 0; |
| Map<String, List<GHPullRequest>> allPullRequests = Maps.newHashMap(); |
| for (NameKey gerritRepoName : repos) { |
| try (Repository gitRepo = repoMgr.openRepository(gerritRepoName)) { |
| String ghRepoName = gerritRepoName.get().split("/")[1]; |
| Optional<GHRepository> githubRepo = getGHRepository(login, gerritRepoName); |
| if (githubRepo.isPresent()) { |
| numPullRequests = |
| collectPullRequestsFromGitHubRepository( |
| numPullRequests, allPullRequests, gitRepo, ghRepoName, githubRepo); |
| } |
| } |
| } |
| return allPullRequests; |
| } |
| |
| private int collectPullRequestsFromGitHubRepository( |
| int numPullRequests, |
| Map<String, List<GHPullRequest>> allPullRequests, |
| Repository gitRepo, |
| String ghRepoName, |
| Optional<GHRepository> githubRepo) |
| throws IncorrectObjectTypeException, IOException { |
| List<GHPullRequest> repoPullRequests = Lists.newArrayList(); |
| |
| int count = numPullRequests; |
| if (count < config.pullRequestListLimit) { |
| for (GHPullRequest ghPullRequest : githubRepo.get().listPullRequests(GHIssueState.OPEN)) { |
| |
| if (isAnyCommitOfPullRequestToBeImported(gitRepo, ghPullRequest)) { |
| repoPullRequests.add(ghPullRequest); |
| count++; |
| } |
| } |
| if (repoPullRequests.size() > 0) { |
| allPullRequests.put(ghRepoName, repoPullRequests); |
| } |
| } else { |
| allPullRequests.put(ghRepoName, null); |
| } |
| return count; |
| } |
| |
| private Optional<GHRepository> getGHRepository(GitHubLogin login, NameKey gerritRepoName) |
| throws IOException { |
| try { |
| return Optional.of(login.getHub().getRepository(gerritRepoName.get())); |
| } catch (FileNotFoundException e) { |
| LOG.debug("GitHub repository {} cannot be found", gerritRepoName.get()); |
| return Optional.absent(); |
| } |
| } |
| |
| private boolean isAnyCommitOfPullRequestToBeImported( |
| Repository gitRepo, GHPullRequest ghPullRequest) |
| throws IncorrectObjectTypeException, IOException { |
| boolean pullRequestToImport = false; |
| try { |
| for (GHPullRequestCommitDetail pullRequestCommit : ghPullRequest.listCommits()) { |
| pullRequestToImport |= |
| qp.get().query(changeQuery.commit(pullRequestCommit.getSha())).entities().isEmpty(); |
| } |
| return pullRequestToImport; |
| } catch (QueryParseException e) { |
| LOG.error("Unable to query Gerrit changes for pull-request " + ghPullRequest.getNumber(), e); |
| return false; |
| } |
| } |
| } |