| // 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.reviewdb.client.PatchSet; |
| import com.google.gerrit.reviewdb.client.Project.NameKey; |
| import com.google.gerrit.reviewdb.client.RevId; |
| import com.google.gerrit.reviewdb.server.ReviewDb; |
| import com.google.gerrit.server.IdentifiedUser; |
| import com.google.gerrit.server.git.GitRepositoryManager; |
| import com.google.gerrit.server.project.ProjectCache; |
| import com.google.gson.JsonArray; |
| import com.google.gson.JsonObject; |
| import com.google.gson.JsonPrimitive; |
| import com.google.gwtorm.server.OrmException; |
| import com.google.gwtorm.server.ResultSet; |
| 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 org.eclipse.jgit.errors.IncorrectObjectTypeException; |
| import org.eclipse.jgit.errors.MissingObjectException; |
| import org.eclipse.jgit.lib.ObjectId; |
| import org.eclipse.jgit.lib.Repository; |
| import org.eclipse.jgit.revwalk.RevWalk; |
| import org.kohsuke.github.GHIssueState; |
| import org.kohsuke.github.GHPerson; |
| import org.kohsuke.github.GHPullRequest; |
| import org.kohsuke.github.GHPullRequestCommitDetail; |
| import org.kohsuke.github.GHRepository; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| 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; |
| |
| @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<ReviewDb> schema; |
| |
| @Inject |
| public PullRequestListController(final ProjectCache projectsCache, |
| final GitRepositoryManager repoMgr, final Provider<ReviewDb> schema, |
| final GitHubConfig config) { |
| this.projectsCache = projectsCache; |
| this.repoMgr = repoMgr; |
| this.schema = schema; |
| this.config = config; |
| } |
| |
| @Override |
| public void doAction(IdentifiedUser user, GitHubLogin hubLogin, |
| HttpServletRequest req, HttpServletResponse resp, ControllerErrors errors) |
| throws ServletException, IOException { |
| 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(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 { |
| GHPerson ghOwner; |
| if (organisation.equals(hubLogin.getMyself().getLogin())) { |
| ghOwner = hubLogin.getMyself(); |
| } else { |
| ghOwner = hubLogin.getHub().getOrganization(organisation); |
| } |
| return getPullRequests( |
| hubLogin, |
| ghOwner, |
| projectsCache.byName(organisation + "/" |
| + Strings.nullToEmpty(repository))); |
| } |
| |
| private Map<String, List<GHPullRequest>> getPullRequests(GitHubLogin login, |
| GHPerson ghOwner, Iterable<NameKey> repos) throws IOException { |
| int numPullRequests = 0; |
| ReviewDb db = schema.get(); |
| Map<String, List<GHPullRequest>> allPullRequests = Maps.newHashMap(); |
| try { |
| for (NameKey gerritRepoName : repos) { |
| Repository gitRepo = repoMgr.openRepository(gerritRepoName); |
| try { |
| String ghRepoName = gerritRepoName.get().split("/")[1]; |
| Optional<GHRepository> githubRepo = |
| getGHRepository(login, gerritRepoName); |
| if (githubRepo.isPresent()) { |
| numPullRequests = |
| collectPullRequestsFromGitHubRepository(numPullRequests, db, |
| allPullRequests, gitRepo, ghRepoName, githubRepo); |
| } |
| } finally { |
| gitRepo.close(); |
| } |
| } |
| return allPullRequests; |
| } finally { |
| db.close(); |
| } |
| } |
| |
| private int collectPullRequestsFromGitHubRepository(int numPullRequests, ReviewDb db, |
| Map<String, List<GHPullRequest>> allPullRequests, Repository gitRepo, |
| String ghRepoName, Optional<GHRepository> githubRepo) |
| throws IncorrectObjectTypeException, IOException { |
| List<GHPullRequest> repoPullRequests = Lists.newArrayList(); |
| |
| if (numPullRequests < config.pullRequestListLimit) { |
| for (GHPullRequest ghPullRequest : githubRepo.get() |
| .listPullRequests(GHIssueState.OPEN)) { |
| |
| if (isAnyCommitOfPullRequestToBeImported(db, gitRepo, |
| ghPullRequest)) { |
| repoPullRequests.add(ghPullRequest); |
| numPullRequests++; |
| } |
| } |
| if (repoPullRequests.size() > 0) { |
| allPullRequests.put(ghRepoName, repoPullRequests); |
| } |
| } else { |
| allPullRequests.put(ghRepoName, null); |
| } |
| return numPullRequests; |
| } |
| |
| 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(ReviewDb db, |
| Repository gitRepo, GHPullRequest ghPullRequest) |
| throws IncorrectObjectTypeException, IOException { |
| boolean pullRequestToImport = false; |
| try (RevWalk gitWalk = new RevWalk(gitRepo)) { |
| for (GHPullRequestCommitDetail pullRequestCommit : ghPullRequest |
| .listCommits()) { |
| ObjectId pullRequestHeadObjectId = |
| ObjectId.fromString(pullRequestCommit.getSha()); |
| |
| try { |
| gitWalk.parseCommit(pullRequestHeadObjectId); |
| |
| ResultSet<PatchSet> patchSets; |
| try { |
| patchSets = |
| db.patchSets().byRevision(new RevId(pullRequestCommit.getSha())); |
| } catch (OrmException e) { |
| LOG.error("Error whilst fetching patch-sets from DB associated to commit " |
| + pullRequestCommit.getSha()); |
| return false; |
| } |
| pullRequestToImport = !patchSets.iterator().hasNext(); |
| patchSets.close(); |
| } catch (MissingObjectException e) { |
| pullRequestToImport = true; |
| } |
| } |
| return pullRequestToImport; |
| } |
| } |
| } |