Merge branch 'master' into createPR
authorAleksey Pivovarov <Aleksey.Pivovarov@jetbrains.com>
Thu, 10 Oct 2013 12:25:14 +0000 (16:25 +0400)
committerAleksey Pivovarov <Aleksey.Pivovarov@jetbrains.com>
Thu, 10 Oct 2013 12:25:14 +0000 (16:25 +0400)
Conflicts:
plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java

12 files changed:
plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java
plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java [new file with mode: 0644]
plugins/github/src/org/jetbrains/plugins/github/api/GithubFullPath.java
plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java
plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form
plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java
plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java [new file with mode: 0644]
plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.form [new file with mode: 0644]
plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.java [new file with mode: 0644]
plugins/github/src/org/jetbrains/plugins/github/util/GithubProjectSettings.java
plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTest.java
plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java

index 3b69d0757273f1d1da4d9e4663f9ec9e93d6af59..d7a342cf96d706e1ddc0a0dcb116478354617ad2 100644 (file)
@@ -17,67 +17,24 @@ package org.jetbrains.plugins.github;
 
 import com.intellij.openapi.actionSystem.AnActionEvent;
 import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.Task;
 import com.intellij.openapi.project.DumbAwareAction;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.Messages;
-import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vcs.VcsException;
-import com.intellij.openapi.vcs.changes.Change;
 import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.Consumer;
-import com.intellij.util.Function;
-import com.intellij.util.ThrowableConsumer;
-import com.intellij.util.ThrowableConvertor;
-import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.containers.Convertor;
-import com.intellij.util.containers.HashMap;
-import com.intellij.util.containers.HashSet;
 import git4idea.DialogManager;
-import git4idea.GitCommit;
-import git4idea.GitLocalBranch;
-import git4idea.GitRemoteBranch;
-import git4idea.branch.GitBranchUtil;
-import git4idea.changes.GitChangeUtils;
-import git4idea.commands.Git;
-import git4idea.commands.GitCommandResult;
-import git4idea.history.GitHistoryUtils;
-import git4idea.repo.GitRemote;
 import git4idea.repo.GitRepository;
-import git4idea.ui.branch.GitCompareBranchesDialog;
-import git4idea.update.GitFetchResult;
-import git4idea.update.GitFetcher;
-import git4idea.util.GitCommitCompareInfo;
 import icons.GithubIcons;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
-import org.jetbrains.plugins.github.api.*;
-import org.jetbrains.plugins.github.exceptions.GithubAuthenticationCanceledException;
 import org.jetbrains.plugins.github.ui.GithubCreatePullRequestDialog;
-import org.jetbrains.plugins.github.util.GithubAuthData;
-import org.jetbrains.plugins.github.util.GithubNotifications;
-import org.jetbrains.plugins.github.util.GithubUrlUtil;
-import org.jetbrains.plugins.github.util.GithubUtil;
-
-import java.io.IOException;
-import java.util.*;
-import java.util.concurrent.atomic.AtomicReference;
+import org.jetbrains.plugins.github.util.*;
 
+import static org.jetbrains.plugins.github.GithubCreatePullRequestWorker.createPullRequestWorker;
 import static org.jetbrains.plugins.github.util.GithubUtil.setVisibleEnabled;
 
 /**
  * @author Aleksey Pivovarov
  */
 public class GithubCreatePullRequestAction extends DumbAwareAction {
-  private static final Logger LOG = GithubUtil.LOG;
-  private static final String CANNOT_CREATE_PULL_REQUEST = "Can't create pull request";
-
   public GithubCreatePullRequestAction() {
     super("Create Pull Request", "Create pull request from current branch", GithubIcons.Github_icon);
   }
@@ -116,543 +73,13 @@ public class GithubCreatePullRequestAction extends DumbAwareAction {
     createPullRequest(project, file);
   }
 
-  static void createPullRequest(@NotNull final Project project, @Nullable final VirtualFile file) {
-    final Git git = ServiceManager.getService(Git.class);
-
-    final GitRepository repository = GithubUtil.getGitRepository(project, file);
-    if (repository == null) {
-      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find git repository");
-      return;
-    }
-    repository.update();
-
-    Pair<GitRemote, String> remote = GithubUtil.findGithubRemote(repository);
-    if (remote == null) {
-      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find GitHub remote");
-      return;
-    }
-    final String remoteUrl = remote.getSecond();
-    final String remoteName = remote.getFirst().getName();
-
-    GithubFullPath userAndRepo = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl);
-    if (userAndRepo == null) {
-      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't process remote: " + remoteUrl);
+  static void createPullRequest(@NotNull Project project, @Nullable VirtualFile file) {
+    GithubCreatePullRequestWorker worker = createPullRequestWorker(project, file);
+    if (worker == null) {
       return;
     }
 
-    final GitLocalBranch currentBranch = repository.getCurrentBranch();
-    if (currentBranch == null) {
-      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "No current branch");
-      return;
-    }
-
-    String upstreamUrl = GithubUtil.findUpstreamRemote(repository);
-    GithubFullPath upstreamUserAndRepo =
-      upstreamUrl == null || !GithubUrlUtil.isGithubUrl(upstreamUrl) ? null : GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(upstreamUrl);
-
-    final Map<String, String> forks = new HashMap<String, String>();
-    final Set<RemoteBranch> branches = new HashSet<RemoteBranch>();
-    addAvailableBranchesFromGit(repository, forks, branches);
-    GithubInfo info = loadGithubInfoAndBranchesWithModal(project, userAndRepo, upstreamUserAndRepo, forks, branches);
-    if (info == null) {
-      return;
-    }
-    final GithubRepoDetailed repo = info.getRepo();
-    final GithubAuthData auth = info.getAuthData();
-
-    GithubRepo parent = repo.getParent();
-    String defaultBranch =
-      parent == null || parent.getDefaultBranch() == null ? null : parent.getUserName() + ":" + parent.getDefaultBranch();
-    Collection<String> suggestions = ContainerUtil.map(branches, new Function<RemoteBranch, String>() {
-      @Override
-      public String fun(RemoteBranch remoteBranch) {
-        return remoteBranch.getReference();
-      }
-    });
-    Consumer<String> showDiff = new Consumer<String>() {
-      @Override
-      public void consume(String ref) {
-        showDiffByRef(project, ref, repository, currentBranch.getName(), auth, forks, branches, repo.getSource());
-      }
-    };
-    final GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(project, suggestions, defaultBranch, showDiff);
+    GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(worker);
     DialogManager.show(dialog);
-    if (!dialog.isOK()) {
-      return;
-    }
-
-    new Task.Backgroundable(project, "Creating pull request...") {
-      @Override
-      public void run(@NotNull ProgressIndicator indicator) {
-        LOG.info("Pushing current branch");
-        indicator.setText("Pushing current branch...");
-        GitCommandResult result = git.push(repository, remoteName, remoteUrl, currentBranch.getName(), true);
-        if (!result.success()) {
-          GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Push failed:<br/>" + result.getErrorOutputAsHtmlString());
-          return;
-        }
-
-        String from = repo.getUserName() + ":" + currentBranch.getName();
-        String onto = dialog.getTargetBranch();
-        String targetUser = onto.substring(0, onto.indexOf(':'));
-
-        GithubFullPath targetRepo = findRepositoryByUser(project, targetUser, forks, auth, repo.getSource());
-        if (targetRepo == null) {
-          GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find repository for specified branch: " + onto);
-          return;
-        }
-
-        LOG.info("Creating pull request");
-        indicator.setText("Creating pull request...");
-        GithubPullRequest request =
-          createPullRequest(project, auth, targetRepo, dialog.getRequestTitle(), dialog.getDescription(), from, onto);
-        if (request == null) {
-          return;
-        }
-
-        GithubNotifications
-          .showInfoURL(project, "Successfully created pull request", "Pull Request #" + request.getNumber(), request.getHtmlUrl());
-      }
-    }.queue();
-  }
-
-  @Nullable
-  private static GithubInfo loadGithubInfoAndBranchesWithModal(@NotNull final Project project,
-                                                               @NotNull final GithubFullPath userAndRepo,
-                                                               @Nullable final GithubFullPath upstreamUserAndRepo,
-                                                               @NotNull final Map<String, String> forks,
-                                                               @NotNull final Set<RemoteBranch> branches) {
-    try {
-      return GithubUtil
-        .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor<ProgressIndicator, GithubInfo, IOException>() {
-          @Override
-          public GithubInfo convert(ProgressIndicator indicator) throws IOException {
-            final AtomicReference<GithubRepoDetailed> reposRef = new AtomicReference<GithubRepoDetailed>();
-            final GithubAuthData auth =
-              GithubUtil.runAndGetValidAuth(project, indicator, new ThrowableConsumer<GithubAuthData, IOException>() {
-                @Override
-                public void consume(GithubAuthData authData) throws IOException {
-                  reposRef.set(GithubApiUtil.getDetailedRepoInfo(authData, userAndRepo.getUser(), userAndRepo.getRepository()));
-                }
-              });
-            addAvailableBranchesFromGithub(project, auth, reposRef.get(), upstreamUserAndRepo, forks, branches);
-            return new GithubInfo(auth, reposRef.get());
-          }
-        });
-    }
-    catch (GithubAuthenticationCanceledException e) {
-      return null;
-    }
-    catch (IOException e) {
-      GithubNotifications.showErrorDialog(project, CANNOT_CREATE_PULL_REQUEST, e);
-      return null;
-    }
-  }
-
-  @Nullable
-  private static GithubFullPath findRepositoryByUser(@NotNull Project project,
-                                                     @NotNull String user,
-                                                     @NotNull Map<String, String> forks,
-                                                     @NotNull GithubAuthData auth,
-                                                     @Nullable GithubRepo source) {
-    for (Map.Entry<String, String> entry : forks.entrySet()) {
-      if (StringUtil.equalsIgnoreCase(user, entry.getKey())) {
-        return new GithubFullPath(entry.getKey(), entry.getValue());
-      }
-    }
-
-    if (source != null) {
-      try {
-        GithubRepoDetailed target = GithubApiUtil.getDetailedRepoInfo(auth, user, source.getName());
-        if (target.getSource() != null && StringUtil.equals(target.getSource().getUserName(), source.getUserName())) {
-          forks.put(target.getUserName(), target.getName());
-          return target.getFullPath();
-        }
-      }
-      catch (IOException ignore) {
-        // such repo may not exist
-      }
-
-      try {
-        GithubRepo fork = GithubApiUtil.findForkByUser(auth, source.getUserName(), source.getName(), user);
-        if (fork != null) {
-          forks.put(fork.getUserName(), fork.getName());
-          return fork.getFullPath();
-        }
-      }
-      catch (IOException e) {
-        GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
-      }
-    }
-
-    return null;
-  }
-
-  @Nullable
-  private static GithubPullRequest createPullRequest(@NotNull Project project,
-                                                     @NotNull GithubAuthData auth,
-                                                     @NotNull GithubFullPath targetRepo,
-                                                     @NotNull String title,
-                                                     @NotNull String description,
-                                                     @NotNull String from,
-                                                     @NotNull String onto) {
-    try {
-      return GithubApiUtil.createPullRequest(auth, targetRepo.getUser(), targetRepo.getRepository(), title, description, from, onto);
-    }
-    catch (IOException e) {
-      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
-      return null;
-    }
-  }
-
-  private static void addAvailableBranchesFromGit(@NotNull GitRepository gitRepository,
-                                                  @NotNull Map<String, String> forks,
-                                                  @NotNull Set<RemoteBranch> branches) {
-    for (GitRemoteBranch remoteBranch : gitRepository.getBranches().getRemoteBranches()) {
-      for (String url : remoteBranch.getRemote().getUrls()) {
-        if (GithubUrlUtil.isGithubUrl(url)) {
-          GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(url);
-          if (path != null) {
-            forks.put(path.getUser(), path.getRepository());
-            branches.add(new RemoteBranch(path.getUser(), remoteBranch.getNameForRemoteOperations(), remoteBranch));
-            break;
-          }
-        }
-      }
-    }
-  }
-
-  private static void addAvailableBranchesFromGithub(@NotNull final Project project,
-                                                     @NotNull final GithubAuthData auth,
-                                                     @NotNull final GithubRepoDetailed repo,
-                                                     @Nullable final GithubFullPath upstreamPath,
-                                                     @NotNull Map<String, String> forks,
-                                                     @NotNull Set<RemoteBranch> branches) {
-    try {
-      final GithubRepo parent = repo.getParent();
-      final GithubRepo source = repo.getSource();
-
-      forks.put(repo.getUserName(), repo.getName());
-      branches.addAll(getBranches(auth, repo.getUserName(), repo.getName()));
-
-      if (parent != null) {
-        forks.put(parent.getUserName(), parent.getName());
-        branches.addAll(getBranches(auth, parent.getUserName(), parent.getName()));
-      }
-
-      if (source != null && !equals(source, parent)) {
-        forks.put(source.getUserName(), source.getName());
-        branches.addAll(getBranches(auth, source.getUserName(), source.getName()));
-      }
-
-      if (upstreamPath != null && !equals(upstreamPath, repo) && !equals(upstreamPath, parent) && !equals(upstreamPath, source)) {
-        forks.put(upstreamPath.getUser(), upstreamPath.getRepository());
-        branches.addAll(getBranches(auth, upstreamPath.getUser(), upstreamPath.getRepository()));
-      }
-    }
-    catch (IOException e) {
-      GithubNotifications.showError(project, "Can't load available branches", e);
-    }
-  }
-
-  @NotNull
-  private static List<RemoteBranch> getBranches(@NotNull GithubAuthData auth, @NotNull final String user, @NotNull final String repo)
-    throws IOException {
-    List<GithubBranch> branches = GithubApiUtil.getRepoBranches(auth, user, repo);
-    return ContainerUtil.map(branches, new Function<GithubBranch, RemoteBranch>() {
-      @Override
-      public RemoteBranch fun(GithubBranch branch) {
-        return new RemoteBranch(user, branch.getName());
-      }
-    });
-  }
-
-  private static boolean equals(@NotNull GithubRepo repo1, @Nullable GithubRepo repo2) {
-    if (repo2 == null) {
-      return false;
-    }
-    return StringUtil.equals(repo1.getUserName(), repo2.getUserName());
-  }
-
-  private static boolean equals(@NotNull GithubFullPath repo1, @Nullable GithubRepo repo2) {
-    if (repo2 == null) {
-      return false;
-    }
-    return StringUtil.equals(repo1.getUser(), repo2.getUserName());
-  }
-
-  private static void showDiffByRef(@NotNull final Project project,
-                                    @Nullable final String ref,
-                                    @NotNull final GitRepository gitRepository,
-                                    @NotNull final String currentBranch,
-                                    @NotNull final GithubAuthData auth,
-                                    @NotNull final Map<String, String> forks,
-                                    @NotNull final Set<RemoteBranch> branches,
-                                    @Nullable final GithubRepo source) {
-    if (ref == null) {
-      return;
-    }
-
-    DiffInfo info = GithubUtil.computeValueInModal(project, "Collecting diff data...", new Convertor<ProgressIndicator, DiffInfo>() {
-      @Override
-      @Nullable
-      public DiffInfo convert(ProgressIndicator indicator) {
-        List<String> list = StringUtil.split(ref, ":");
-        assert list.size() == 2 : ref;
-        final String user = list.get(0);
-        final String branch = list.get(1);
-
-        TargetBranchInfo targetBranchInfo;
-        RemoteBranch remoteBranch = findRemoteBranch(branches, user, branch);
-        if (remoteBranch != null && remoteBranch.getRemoteBranch() != null) {
-          targetBranchInfo = getTargetBranchInfo(remoteBranch.getRemoteBranch());
-        }
-        else {
-          GithubFullPath forkPath = findRepositoryByUser(project, user, forks, auth, source);
-          if (forkPath == null) {
-            ApplicationManager.getApplication().invokeLater(new Runnable() {
-              @Override
-              public void run() {
-                GithubNotifications.showErrorDialog(project, "Can't show diff", "Can't find fork for user '" + user + "'");
-              }
-            }, indicator.getModalityState());
-            return null;
-          }
-
-          targetBranchInfo = findRemote(branch, gitRepository, forkPath);
-          if (targetBranchInfo == null) {
-            final AtomicReference<Integer> responseRef = new AtomicReference<Integer>();
-            ApplicationManager.getApplication().invokeAndWait(new Runnable() {
-              @Override
-              public void run() {
-                responseRef.set(GithubNotifications.showYesNoDialog(project, "Can't find remote", "Configure remote for '" + user + "'?"));
-              }
-            }, indicator.getModalityState());
-            if (responseRef.get() != Messages.YES) {
-              return null;
-            }
-
-            targetBranchInfo = configureRemote(project, user, branch, gitRepository, forkPath);
-          }
-        }
-        if (targetBranchInfo == null) {
-          return null;
-        }
-
-        GitFetchResult result = new GitFetcher(project, indicator, false)
-          .fetch(gitRepository.getRoot(), targetBranchInfo.getRemote(), targetBranchInfo.getBranchNameForRemoteOperations());
-        if (!result.isSuccess()) {
-          GitFetcher.displayFetchResult(project, result, null, result.getErrors());
-          return null;
-        }
-
-        DiffInfo info = getDiffInfo(project, gitRepository, currentBranch, targetBranchInfo.getBranchNameForLocalOperations());
-        if (info == null) {
-          ApplicationManager.getApplication().invokeLater(new Runnable() {
-            @Override
-            public void run() {
-              GithubNotifications.showErrorDialog(project, "Can't show diff", "Can't get diff info");
-            }
-          }, indicator.getModalityState());
-          return null;
-        }
-        return info;
-      }
-    });
-    if (info == null) {
-      return;
-    }
-
-    GitCompareBranchesDialog dialog = new GitCompareBranchesDialog(project, info.getTo(), info.getFrom(), info.getInfo(), gitRepository);
-    dialog.show();
-  }
-
-  private static TargetBranchInfo getTargetBranchInfo(@NotNull GitRemoteBranch remoteBranch) {
-    return new TargetBranchInfo(remoteBranch.getRemote().getName(), remoteBranch.getNameForRemoteOperations());
-  }
-
-  @Nullable
-  private static TargetBranchInfo findRemote(@NotNull String branch,
-                                             @NotNull GitRepository gitRepository,
-                                             @NotNull GithubFullPath forkPath) {
-    GitRemote remote = GithubUtil.findGithubRemote(gitRepository, forkPath);
-    return remote == null ? null : new TargetBranchInfo(remote.getName(), branch);
-  }
-
-  @Nullable
-  private static TargetBranchInfo configureRemote(@NotNull Project project,
-                                                  @NotNull String user,
-                                                  @NotNull String branch,
-                                                  @NotNull GitRepository gitRepository,
-                                                  @NotNull GithubFullPath forkPath) {
-    String url = GithubUrlUtil.getCloneUrl(forkPath);
-
-    if (GithubUtil.addGithubRemote(project, gitRepository, user, url)) {
-      return new TargetBranchInfo(user, branch);
-    }
-    else {
-      return null;
-    }
-  }
-
-  @Nullable
-  private static RemoteBranch findRemoteBranch(@NotNull Set<RemoteBranch> branches, @NotNull String user, @NotNull String branch) {
-    for (RemoteBranch remoteBranch : branches) {
-      if (StringUtil.equalsIgnoreCase(user, remoteBranch.getUser()) && StringUtil.equals(branch, remoteBranch.getBranch())) {
-        return remoteBranch;
-      }
-    }
-
-    return null;
-  }
-
-  @Nullable
-  private static DiffInfo getDiffInfo(@NotNull final Project project,
-                                      @NotNull final GitRepository repository,
-                                      @NotNull final String currentBranch,
-                                      @NotNull final String targetBranch) {
-    try {
-      List<GitCommit> commits = GitHistoryUtils.history(project, repository.getRoot(), targetBranch + "..");
-      Collection<Change> diff = GitChangeUtils.getDiff(repository.getProject(), repository.getRoot(), targetBranch, currentBranch, null);
-      GitCommitCompareInfo info = new GitCommitCompareInfo(GitCommitCompareInfo.InfoType.BRANCH_TO_HEAD);
-      info.put(repository, diff);
-      info.put(repository, Pair.<List<GitCommit>, List<GitCommit>>create(new ArrayList<GitCommit>(), commits));
-      return new DiffInfo(info, currentBranch, targetBranch);
-    }
-    catch (VcsException e) {
-      LOG.info(e);
-      return null;
-    }
-  }
-
-  private static class RemoteBranch {
-    @NotNull final String myUser;
-    @NotNull final String myBranch;
-
-    @Nullable final GitRemoteBranch myRemoteBranch;
-
-    private RemoteBranch(@NotNull String user, @NotNull String branch) {
-      this(user, branch, null);
-    }
-
-    public RemoteBranch(@NotNull String user, @NotNull String branch, @Nullable GitRemoteBranch localBranch) {
-      myUser = user;
-      myBranch = branch;
-      myRemoteBranch = localBranch;
-    }
-
-    @NotNull
-    public String getReference() {
-      return myUser + ":" + myBranch;
-    }
-
-    @NotNull
-    public String getUser() {
-      return myUser;
-    }
-
-    @NotNull
-    public String getBranch() {
-      return myBranch;
-    }
-
-    @Nullable
-    public GitRemoteBranch getRemoteBranch() {
-      return myRemoteBranch;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) return true;
-      if (o == null || getClass() != o.getClass()) return false;
-
-      RemoteBranch that = (RemoteBranch)o;
-
-      if (!StringUtil.equals(myUser, that.myUser)) return false;
-      if (!StringUtil.equals(myBranch, that.myBranch)) return false;
-
-      return true;
-    }
-
-    @Override
-    public int hashCode() {
-      int result = myUser.hashCode();
-      result = 31 * result + myBranch.hashCode();
-      return result;
-    }
-  }
-
-  private static class GithubInfo {
-    @NotNull private final GithubRepoDetailed myRepo;
-    @NotNull private final GithubAuthData myAuthData;
-
-    private GithubInfo(@NotNull GithubAuthData authData, @NotNull GithubRepoDetailed repo) {
-      myAuthData = authData;
-      myRepo = repo;
-    }
-
-    @NotNull
-    public GithubRepoDetailed getRepo() {
-      return myRepo;
-    }
-
-    @NotNull
-    public GithubAuthData getAuthData() {
-      return myAuthData;
-    }
-  }
-
-  private static class DiffInfo {
-    @NotNull private final GitCommitCompareInfo myInfo;
-    @NotNull private final String myFrom;
-    @NotNull private final String myTo;
-
-    private DiffInfo(@NotNull GitCommitCompareInfo info, @NotNull String from, @NotNull String to) {
-      myInfo = info;
-      myFrom = from;
-      myTo = to;
-    }
-
-    @NotNull
-    public GitCommitCompareInfo getInfo() {
-      return myInfo;
-    }
-
-    @NotNull
-    public String getFrom() {
-      return myFrom;
-    }
-
-    @NotNull
-    public String getTo() {
-      return myTo;
-    }
-  }
-
-  private static class TargetBranchInfo {
-    @NotNull private final String myRemote;
-    @NotNull private final String myName;
-    @NotNull private final String myNameAtRemote;
-
-    private TargetBranchInfo(@NotNull String remote, @NotNull String nameAtRemote) {
-      myRemote = remote;
-      myNameAtRemote = GitBranchUtil.stripRefsPrefix(nameAtRemote);
-      myName = myRemote + "/" + myNameAtRemote;
-    }
-
-    @NotNull
-    public String getRemote() {
-      return myRemote;
-    }
-
-    @NotNull
-    public String getBranchNameForLocalOperations() {
-      return myName;
-    }
-
-    @NotNull
-    public String getBranchNameForRemoteOperations() {
-      return myNameAtRemote;
-    }
   }
-}
+}
\ No newline at end of file
diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java
new file mode 100644 (file)
index 0000000..1b7819a
--- /dev/null
@@ -0,0 +1,511 @@
+package org.jetbrains.plugins.github;
+
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vcs.VcsException;
+import com.intellij.openapi.vcs.changes.Change;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.Function;
+import com.intellij.util.ThrowableConvertor;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.Convertor;
+import git4idea.DialogManager;
+import git4idea.GitCommit;
+import git4idea.GitLocalBranch;
+import git4idea.GitRemoteBranch;
+import git4idea.changes.GitChangeUtils;
+import git4idea.commands.Git;
+import git4idea.commands.GitCommandResult;
+import git4idea.history.GitHistoryUtils;
+import git4idea.repo.GitRemote;
+import git4idea.repo.GitRepository;
+import git4idea.ui.branch.GitCompareBranchesDialog;
+import git4idea.update.GitFetchResult;
+import git4idea.update.GitFetcher;
+import git4idea.util.GitCommitCompareInfo;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.github.api.*;
+import org.jetbrains.plugins.github.exceptions.GithubAuthenticationCanceledException;
+import org.jetbrains.plugins.github.ui.GithubSelectForkDialog;
+import org.jetbrains.plugins.github.util.GithubAuthData;
+import org.jetbrains.plugins.github.util.GithubNotifications;
+import org.jetbrains.plugins.github.util.GithubUrlUtil;
+import org.jetbrains.plugins.github.util.GithubUtil;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * @author Aleksey Pivovarov
+ */
+public class GithubCreatePullRequestWorker {
+  private static final Logger LOG = GithubUtil.LOG;
+  private static final String CANNOT_CREATE_PULL_REQUEST = "Can't create pull request";
+
+  @NotNull private final Project myProject;
+  @NotNull private final Git myGit;
+  @NotNull private final GitRepository myGitRepository;
+  @NotNull private final GithubFullPath myPath;
+  @NotNull private final String myRemoteName;
+  @NotNull private final String myRemoteUrl;
+  @NotNull private final String myCurrentBranch;
+  @NotNull private final GithubAuthData myAuth;
+
+  private volatile GithubFullPath myForkPath;
+  private volatile String myTargetRemote;
+
+  private GithubCreatePullRequestWorker(@NotNull Project project,
+                                        @NotNull Git git,
+                                        @NotNull GitRepository gitRepository,
+                                        @NotNull GithubFullPath path,
+                                        @NotNull String remoteName,
+                                        @NotNull String remoteUrl,
+                                        @NotNull String currentBranch,
+                                        @NotNull GithubAuthData auth) {
+    myProject = project;
+    myGit = git;
+    myGitRepository = gitRepository;
+    myPath = path;
+    myRemoteName = remoteName;
+    myRemoteUrl = remoteUrl;
+    myCurrentBranch = currentBranch;
+    myAuth = auth;
+  }
+
+  @NotNull
+  public Project getProject() {
+    return myProject;
+  }
+
+  @Nullable
+  public static GithubCreatePullRequestWorker createPullRequestWorker(@NotNull final Project project, @Nullable final VirtualFile file) {
+    Git git = ServiceManager.getService(Git.class);
+
+    GitRepository gitRepository = GithubUtil.getGitRepository(project, file);
+    if (gitRepository == null) {
+      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find git repository");
+      return null;
+    }
+    gitRepository.update();
+
+    Pair<GitRemote, String> remote = GithubUtil.findGithubRemote(gitRepository);
+    if (remote == null) {
+      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find GitHub remote");
+      return null;
+    }
+    String remoteName = remote.getFirst().getName();
+    String remoteUrl = remote.getSecond();
+    GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl);
+    if (path == null) {
+      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't process remote: " + remoteUrl);
+      return null;
+    }
+
+    GitLocalBranch currentBranch = gitRepository.getCurrentBranch();
+    if (currentBranch == null) {
+      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "No current branch");
+      return null;
+    }
+
+    GithubAuthData auth;
+    try {
+      auth = GithubUtil
+        .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor<ProgressIndicator, GithubAuthData, IOException>() {
+          @Override
+          public GithubAuthData convert(ProgressIndicator indicator) throws IOException {
+            return GithubUtil.getValidAuthDataFromConfig(project, indicator);
+          }
+        });
+    }
+    catch (GithubAuthenticationCanceledException e) {
+      return null;
+    }
+    catch (IOException e) {
+      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
+      return null;
+    }
+
+    return new GithubCreatePullRequestWorker(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch.getName(), auth);
+  }
+
+  @Nullable
+  public GithubTargetInfo setTarget(@NotNull final GithubFullPath forkPath) {
+    try {
+      GithubInfo info =
+        GithubUtil.computeValueInModal(myProject, "Access to GitHub", new ThrowableConvertor<ProgressIndicator, GithubInfo, IOException>() {
+          @Override
+          public GithubInfo convert(ProgressIndicator indicator) throws IOException {
+            // configure remote
+            GitRemote targetRemote = GithubUtil.findGithubRemote(myGitRepository, forkPath);
+            String targetRemoteName = targetRemote == null ? null : targetRemote.getName();
+            if (targetRemoteName == null) {
+              final AtomicReference<Integer> responseRef = new AtomicReference<Integer>();
+              ApplicationManager.getApplication().invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                  responseRef.set(GithubNotifications
+                                    .showYesNoDialog(myProject, "Can't find remote", "Configure remote for '" + forkPath.getUser() + "'?"));
+                }
+              }, indicator.getModalityState());
+              if (responseRef.get() == Messages.YES) {
+                targetRemoteName = configureRemote(myProject, myGitRepository, forkPath);
+              }
+            }
+
+            // load available branches
+            List<String> branches = ContainerUtil.map(GithubApiUtil.getRepoBranches(myAuth, forkPath.getUser(), forkPath.getRepository()),
+                                                      new Function<GithubBranch, String>() {
+                                                        @Override
+                                                        public String fun(GithubBranch githubBranch) {
+                                                          return githubBranch.getName();
+                                                        }
+                                                      });
+
+            // fetch
+            if (targetRemoteName != null) {
+              GitFetchResult result = new GitFetcher(myProject, indicator, false).fetch(myGitRepository.getRoot(), targetRemoteName, null);
+              if (!result.isSuccess()) {
+                GitFetcher.displayFetchResult(myProject, result, null, result.getErrors());
+                targetRemoteName = null;
+              }
+            }
+
+            return new GithubInfo(branches, targetRemoteName);
+          }
+        });
+
+      myForkPath = forkPath;
+      myTargetRemote = info.getTargetRemote();
+      return new GithubTargetInfo(info.getBranches(), myTargetRemote != null);
+    }
+    catch (GithubAuthenticationCanceledException e) {
+      return null;
+    }
+    catch (IOException e) {
+      GithubNotifications.showErrorDialog(myProject, CANNOT_CREATE_PULL_REQUEST, e);
+      return null;
+    }
+  }
+
+  public void showDiffDialog(@NotNull String branch) {
+    if (myTargetRemote != null) {
+      showDiffByRef(myProject, branch, myGitRepository, myTargetRemote, myCurrentBranch);
+    }
+  }
+
+  @Nullable
+  public GithubFullPath showTargetDialog() {
+    final GithubInfo2 info = getAvailableForksInModal(myProject, myGitRepository, myAuth, myPath);
+    if (info == null) {
+      return null;
+    }
+
+    Convertor<String, GithubFullPath> getForkPath = new Convertor<String, GithubFullPath>() {
+      @Nullable
+      @Override
+      public GithubFullPath convert(@NotNull final String user) {
+        return GithubUtil.computeValueInModal(myProject, "Access to GitHub", new Convertor<ProgressIndicator, GithubFullPath>() {
+          @Nullable
+          @Override
+          public GithubFullPath convert(ProgressIndicator o) {
+            return findRepositoryByUser(myProject, user, info.getForks(), myAuth, info.getSource());
+          }
+        });
+      }
+    };
+    GithubSelectForkDialog dialog = new GithubSelectForkDialog(myProject, info.getForks(), getForkPath);
+    DialogManager.show(dialog);
+    if (!dialog.isOK()) {
+      return null;
+    }
+    return dialog.getPath();
+  }
+
+  public void performAction(@NotNull final String title, @NotNull final String description, @NotNull final String targetBranch) {
+    new Task.Backgroundable(myProject, "Creating pull request...") {
+      @Override
+      public void run(@NotNull ProgressIndicator indicator) {
+        LOG.info("Pushing current branch");
+        indicator.setText("Pushing current branch...");
+        GitCommandResult result = myGit.push(myGitRepository, myRemoteName, myRemoteUrl, myCurrentBranch, true);
+        if (!result.success()) {
+          GithubNotifications.showError(myProject, CANNOT_CREATE_PULL_REQUEST, "Push failed:<br/>" + result.getErrorOutputAsHtmlString());
+          return;
+        }
+
+        String baseBranch = myPath.getUser() + ":" + myCurrentBranch;
+
+        LOG.info("Creating pull request");
+        indicator.setText("Creating pull request...");
+        GithubPullRequest request = createPullRequest(myProject, myAuth, myForkPath, title, description, baseBranch, targetBranch);
+        if (request == null) {
+          return;
+        }
+
+        GithubNotifications
+          .showInfoURL(myProject, "Successfully created pull request", "Pull Request #" + request.getNumber(), request.getHtmlUrl());
+      }
+    }.queue();
+  }
+
+  @Nullable
+  private static String configureRemote(@NotNull Project project, @NotNull GitRepository gitRepository, @NotNull GithubFullPath forkPath) {
+    String url = GithubUrlUtil.getCloneUrl(forkPath);
+
+    if (GithubUtil.addGithubRemote(project, gitRepository, forkPath.getUser(), url)) {
+      return forkPath.getUser();
+    }
+    else {
+      return null;
+    }
+  }
+
+  @Nullable
+  private static GithubPullRequest createPullRequest(@NotNull Project project,
+                                                     @NotNull GithubAuthData auth,
+                                                     @NotNull GithubFullPath targetRepo,
+                                                     @NotNull String title,
+                                                     @NotNull String description,
+                                                     @NotNull String from,
+                                                     @NotNull String onto) {
+    try {
+      return GithubApiUtil.createPullRequest(auth, targetRepo.getUser(), targetRepo.getRepository(), title, description, from, onto);
+    }
+    catch (IOException e) {
+      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
+      return null;
+    }
+  }
+
+  private static void showDiffByRef(@NotNull final Project project,
+                                    @Nullable final String branch,
+                                    @NotNull final GitRepository gitRepository,
+                                    @NotNull final String targetRemoteName,
+                                    @NotNull final String currentBranch) {
+    if (branch == null) {
+      return;
+    }
+
+    DiffInfo info = GithubUtil.computeValueInModal(project, "Collecting diff data...", new Convertor<ProgressIndicator, DiffInfo>() {
+      @Override
+      @Nullable
+      public DiffInfo convert(ProgressIndicator indicator) {
+        return getDiffInfo(project, gitRepository, currentBranch, targetRemoteName + "/" + branch);
+      }
+    });
+    if (info == null) {
+      GithubNotifications.showErrorDialog(project, "Can't show diff", "Can't get diff info");
+      return;
+    }
+
+    GitCompareBranchesDialog dialog = new GitCompareBranchesDialog(project, info.getTo(), info.getFrom(), info.getInfo(), gitRepository);
+    dialog.show();
+  }
+
+  @Nullable
+  private static DiffInfo getDiffInfo(@NotNull final Project project,
+                                      @NotNull final GitRepository repository,
+                                      @NotNull final String currentBranch,
+                                      @NotNull final String targetBranch) {
+    try {
+      List<GitCommit> commits = GitHistoryUtils.history(project, repository.getRoot(), targetBranch + "..");
+      Collection<Change> diff = GitChangeUtils.getDiff(repository.getProject(), repository.getRoot(), targetBranch, currentBranch, null);
+      GitCommitCompareInfo info = new GitCommitCompareInfo(GitCommitCompareInfo.InfoType.BRANCH_TO_HEAD);
+      info.put(repository, diff);
+      info.put(repository, Pair.<List<GitCommit>, List<GitCommit>>create(new ArrayList<GitCommit>(), commits));
+      return new DiffInfo(info, currentBranch, targetBranch);
+    }
+    catch (VcsException e) {
+      LOG.info(e);
+      return null;
+    }
+  }
+
+  @Nullable
+  private static GithubInfo2 getAvailableForksInModal(@NotNull final Project project,
+                                                      @NotNull final GitRepository gitRepository,
+                                                      @NotNull final GithubAuthData auth,
+                                                      @NotNull final GithubFullPath path) {
+    return GithubUtil.computeValueInModal(project, "Access to GitHub", new Convertor<ProgressIndicator, GithubInfo2>() {
+      @Nullable
+      @Override
+      public GithubInfo2 convert(ProgressIndicator indicator) {
+        try {
+          final Set<GithubFullPath> forks = new HashSet<GithubFullPath>();
+
+          // GitHub
+          GithubRepoDetailed repo = GithubApiUtil.getDetailedRepoInfo(auth, path.getUser(), path.getRepository());
+          forks.add(path);
+          if (repo.getParent() != null) {
+            forks.add(repo.getParent().getFullPath());
+          }
+          if (repo.getSource() != null) {
+            forks.add(repo.getSource().getFullPath());
+          }
+
+          // Git
+          forks.addAll(getAvailableForksFromGit(gitRepository));
+
+          GithubRepo forkTreeRoot = repo.getSource() == null ? repo : repo.getSource();
+          return new GithubInfo2(forks, forkTreeRoot);
+        }
+        catch (GithubAuthenticationCanceledException e) {
+          return null;
+        }
+        catch (IOException e) {
+          GithubNotifications.showErrorDialog(project, CANNOT_CREATE_PULL_REQUEST, e);
+          return null;
+        }
+      }
+    });
+  }
+
+  @NotNull
+  private static List<GithubFullPath> getAvailableForksFromGit(@NotNull GitRepository gitRepository) {
+    List<GithubFullPath> forks = new ArrayList<GithubFullPath>();
+    for (GitRemoteBranch remoteBranch : gitRepository.getBranches().getRemoteBranches()) {
+      for (String url : remoteBranch.getRemote().getUrls()) {
+        if (GithubUrlUtil.isGithubUrl(url)) {
+          GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(url);
+          if (path != null) {
+            forks.add(path);
+            break;
+          }
+        }
+      }
+    }
+    return forks;
+  }
+
+  @Nullable
+  private static GithubFullPath findRepositoryByUser(@NotNull Project project,
+                                                     @NotNull String user,
+                                                     @NotNull Set<GithubFullPath> forks,
+                                                     @NotNull GithubAuthData auth,
+                                                     @NotNull GithubRepo source) {
+    for (GithubFullPath path : forks) {
+      if (StringUtil.equalsIgnoreCase(user, path.getUser())) {
+        return path;
+      }
+    }
+
+    try {
+      GithubRepoDetailed target = GithubApiUtil.getDetailedRepoInfo(auth, user, source.getName());
+      if (target.getSource() != null && StringUtil.equals(target.getSource().getUserName(), source.getUserName())) {
+        return target.getFullPath();
+      }
+    }
+    catch (IOException ignore) {
+      // such repo may not exist
+    }
+
+    try {
+      GithubRepo fork = GithubApiUtil.findForkByUser(auth, source.getUserName(), source.getName(), user);
+      if (fork != null) {
+        return fork.getFullPath();
+      }
+    }
+    catch (IOException e) {
+      GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
+    }
+
+    return null;
+  }
+
+  private static class GithubInfo {
+    @NotNull private final List<String> myBranches;
+    @Nullable private final String myTargetRemote;
+
+    private GithubInfo(@NotNull List<String> repo, @Nullable String targetRemote) {
+      myBranches = repo;
+      myTargetRemote = targetRemote;
+    }
+
+    @NotNull
+    public List<String> getBranches() {
+      return myBranches;
+    }
+
+    @Nullable
+    public String getTargetRemote() {
+      return myTargetRemote;
+    }
+  }
+
+  private static class GithubInfo2 {
+    @NotNull private final Set<GithubFullPath> myForks;
+    @NotNull private final GithubRepo mySource;
+
+    private GithubInfo2(@NotNull Set<GithubFullPath> forks, @NotNull GithubRepo source) {
+      myForks = forks;
+      mySource = source;
+    }
+
+    @NotNull
+    public Set<GithubFullPath> getForks() {
+      return myForks;
+    }
+
+    @NotNull
+    public GithubRepo getSource() {
+      return mySource;
+    }
+  }
+
+  public static class GithubTargetInfo {
+    @NotNull private final List<String> myBranches;
+    private final boolean myCanShowDiff;
+
+    private GithubTargetInfo(@NotNull List<String> branches, boolean canShowDiff) {
+      myBranches = branches;
+      myCanShowDiff = canShowDiff;
+    }
+
+    @NotNull
+    public List<String> getBranches() {
+      return myBranches;
+    }
+
+    public boolean isCanShowDiff() {
+      return myCanShowDiff;
+    }
+  }
+
+  private static class DiffInfo {
+    @NotNull private final GitCommitCompareInfo myInfo;
+    @NotNull private final String myFrom;
+    @NotNull private final String myTo;
+
+    private DiffInfo(@NotNull GitCommitCompareInfo info, @NotNull String from, @NotNull String to) {
+      myInfo = info;
+      myFrom = from;
+      myTo = to;
+    }
+
+    @NotNull
+    public GitCommitCompareInfo getInfo() {
+      return myInfo;
+    }
+
+    @NotNull
+    public String getFrom() {
+      return myFrom;
+    }
+
+    @NotNull
+    public String getTo() {
+      return myTo;
+    }
+  }
+}
index c2c7c7f63d8658e1558fe4220644133de06d38a2..740d34a2837f6c832e371003f537b4e864e996e7 100644 (file)
@@ -41,7 +41,7 @@ public class GithubFullPath {
   }
 
   @NotNull
-  public String toString() {
+  public String getFullName() {
     return myUserName + '/' + myRepositoryName;
   }
 
index e0c648e1656888485c035042651995bff4d4991a..73a7066612249118ca41dac8cb00b0c6e373beab 100644 (file)
  */
 package org.jetbrains.plugins.github.ui;
 
-import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.DialogWrapper;
 import com.intellij.openapi.ui.ValidationInfo;
 import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.util.Consumer;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.TestOnly;
+import org.jetbrains.plugins.github.GithubCreatePullRequestWorker;
+import org.jetbrains.plugins.github.api.GithubFullPath;
 import org.jetbrains.plugins.github.util.GithubProjectSettings;
 
 import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.util.Collection;
-import java.util.regex.Pattern;
+import java.util.Collections;
 
 /**
  * @author Aleksey Pivovarov
  */
 public class GithubCreatePullRequestDialog extends DialogWrapper {
   @NotNull private final GithubCreatePullRequestPanel myGithubCreatePullRequestPanel;
-  @NotNull private static final Pattern GITHUB_REPO_PATTERN = Pattern.compile("[a-zA-Z0-9_.-]+:[a-zA-Z0-9_.-]+");
-  @NotNull private final Project myProject;
+  @NotNull private final GithubCreatePullRequestWorker myWorker;
+  @NotNull private final GithubProjectSettings myProjectSettings;
+
+  public GithubCreatePullRequestDialog(@NotNull GithubCreatePullRequestWorker worker) {
+    super(worker.getProject(), true);
+    myWorker = worker;
+
+    myProjectSettings = GithubProjectSettings.getInstance(myWorker.getProject());
+
+    myGithubCreatePullRequestPanel = new GithubCreatePullRequestPanel(new ActionListener() {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        myWorker.showDiffDialog(myGithubCreatePullRequestPanel.getBranch());
+      }
+    }, new ActionListener() {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        showTargetDialog();
+      }
+    }
+    );
+
+    setTitle("Create Pull Request");
+    init();
+  }
 
-  public GithubCreatePullRequestDialog(@NotNull final Project project,
-                                       @NotNull Collection<String> branches,
-                                       @Nullable String suggestedBranch,
-                                       @NotNull Consumer<String> showDiff) {
-    super(project, true);
-    myGithubCreatePullRequestPanel = new GithubCreatePullRequestPanel(showDiff);
+  @Override
+  public void show() {
+    GithubFullPath defaultForkPath = myProjectSettings.getCreatePullRequestDefaultRepo();
+    if (defaultForkPath != null) {
+      setTarget(defaultForkPath);
+    }
+    else {
+      showTargetDialog();
+    }
+    super.show();
+  }
 
+  private void showTargetDialog() {
+    GithubFullPath forkPath = myWorker.showTargetDialog();
+    if (forkPath == null) {
+      doCancelAction();
+      return;
+    }
+    setTarget(forkPath);
+  }
+
+  private void setTarget(@NotNull GithubFullPath forkPath) {
+    GithubCreatePullRequestWorker.GithubTargetInfo forkInfo = myWorker.setTarget(forkPath);
+    if (forkInfo == null) {
+      doCancelAction();
+      return;
+    }
+    myProjectSettings.setCreatePullRequestDefaultRepo(forkPath);
+    myGithubCreatePullRequestPanel.setDiffEnabled(forkInfo.isCanShowDiff());
+    updateBranches(forkInfo.getBranches(), forkPath);
+  }
+
+  private void updateBranches(@NotNull Collection<String> branches, @NotNull GithubFullPath forkPath) {
     myGithubCreatePullRequestPanel.setBranches(branches);
 
-    myProject = project;
-    String configBranch = GithubProjectSettings.getInstance(myProject).getCreatePullRequestDefaultBranch();
-    myGithubCreatePullRequestPanel.setSelectedBranch(configBranch != null ? configBranch : suggestedBranch);
+    String configBranch = myProjectSettings.getCreatePullRequestDefaultBranch();
+    if (configBranch != null) myGithubCreatePullRequestPanel.setSelectedBranch(configBranch);
 
-    setTitle("Create Pull Request");
-    init();
+    myGithubCreatePullRequestPanel.setForkName(forkPath.getFullName());
+  }
+
+  @Override
+  protected void doOKAction() {
+    super.doOKAction();
+    myProjectSettings.setCreatePullRequestDefaultBranch(getTargetBranch());
+    myWorker.performAction(getRequestTitle(), getDescription(), getTargetBranch());
   }
 
   @Nullable
@@ -77,47 +133,51 @@ public class GithubCreatePullRequestDialog extends DialogWrapper {
   }
 
   @NotNull
-  public String getRequestTitle() {
+  private String getRequestTitle() {
     return myGithubCreatePullRequestPanel.getTitle();
   }
 
   @NotNull
-  public String getDescription() {
+  private String getDescription() {
     return myGithubCreatePullRequestPanel.getDescription();
   }
 
   @NotNull
-  public String getTargetBranch() {
+  private String getTargetBranch() {
     return myGithubCreatePullRequestPanel.getBranch();
   }
 
-  @Override
-  protected void doOKAction() {
-    super.doOKAction();
-    GithubProjectSettings.getInstance(myProject).setCreatePullRequestDefaultBranch(getTargetBranch());
-  }
-
   @Nullable
   @Override
   protected ValidationInfo doValidate() {
     if (StringUtil.isEmptyOrSpaces(getRequestTitle())) {
       return new ValidationInfo("Title can't be empty'", myGithubCreatePullRequestPanel.getTitleTextField());
     }
-
-    if (!GITHUB_REPO_PATTERN.matcher(getTargetBranch()).matches()) {
-      return new ValidationInfo("Branch must be specified like 'username:branch'", myGithubCreatePullRequestPanel.getBranchEditor());
-    }
-
     return null;
   }
 
   @TestOnly
-  public void setRequestTitle(String title) {
+  public void testSetRequestTitle(String title) {
     myGithubCreatePullRequestPanel.setTitle(title);
   }
 
   @TestOnly
-  public void setBranch(String branch) {
-    myGithubCreatePullRequestPanel.setSelectedBranch(branch);
+  public void testSetBranch(String branch) {
+    myGithubCreatePullRequestPanel.setBranches(Collections.singleton(branch));
+  }
+
+  @TestOnly
+  public void testCreatePullRequest() {
+    myWorker.performAction(getRequestTitle(), getDescription(), getTargetBranch());
+  }
+
+  @TestOnly
+  public void testSetTarget(@NotNull GithubFullPath forkPath) {
+    GithubCreatePullRequestWorker.GithubTargetInfo forkInfo = myWorker.setTarget(forkPath);
+    if (forkInfo == null) {
+      doCancelAction();
+      return;
+    }
+    myGithubCreatePullRequestPanel.setDiffEnabled(forkInfo.isCanShowDiff());
   }
 }
index 46864f0554050681b7fc51097bd0224bec567150..ed383cf50a11c29554df1006db5e52ca6717530c 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.github.ui.GithubCreatePullRequestPanel">
-  <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="4" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+  <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
     <margin top="0" left="0" bottom="0" right="0"/>
     <constraints>
       <xy x="20" y="20" width="500" height="400"/>
@@ -10,7 +10,7 @@
     <children>
       <component id="3f5fd" class="com.intellij.ui.components.JBLabel">
         <constraints>
-          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
         </constraints>
         <properties>
           <text value="Target branch:"/>
@@ -18,7 +18,7 @@
       </component>
       <component id="d2b10" class="com.intellij.ui.components.JBLabel">
         <constraints>
-          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
         </constraints>
         <properties>
           <text value="Title:"/>
@@ -26,7 +26,7 @@
       </component>
       <component id="f7387" class="com.intellij.ui.components.JBLabel">
         <constraints>
-          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+          <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
         </constraints>
         <properties>
           <text value="Description:"/>
@@ -34,7 +34,7 @@
       </component>
       <component id="996e9" class="javax.swing.JTextField" binding="myTitleTextField">
         <constraints>
-          <grid row="1" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+          <grid row="2" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
             <preferred-size width="150" height="-1"/>
           </grid>
         </constraints>
       </component>
       <component id="78a64" class="com.intellij.openapi.ui.ComboBox" binding="myBranchComboBox">
         <constraints>
-          <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
+          <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
         </constraints>
         <properties>
-          <editable value="true"/>
+          <editable value="false"/>
           <toolTipText value="Target branch in format 'user:branch', where user - owner of the target repository"/>
         </properties>
       </component>
       <scrollpane id="61e54" class="com.intellij.ui.components.JBScrollPane">
         <constraints>
-          <grid row="3" column="0" row-span="1" col-span="3" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false">
+          <grid row="4" column="0" row-span="1" col-span="3" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false">
             <minimum-size width="150" height="50"/>
           </grid>
         </constraints>
         <properties/>
-        <border type="none"/>
+        <border type="empty"/>
         <children>
           <component id="21aa4" class="javax.swing.JTextArea" binding="myDescriptionTextArea">
             <constraints/>
       </scrollpane>
       <component id="90c93" class="javax.swing.JButton" binding="myShowDiffButton">
         <constraints>
-          <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+          <grid row="1" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
         </constraints>
         <properties>
           <text value="Show Diff"/>
         </properties>
       </component>
+      <component id="fb73f" class="javax.swing.JLabel">
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="Target repository:"/>
+        </properties>
+      </component>
+      <component id="a5106" class="javax.swing.JButton" binding="mySelectForkButton">
+        <constraints>
+          <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="Select Fork"/>
+        </properties>
+      </component>
+      <component id="e5548" class="javax.swing.JLabel" binding="myForkLabel">
+        <constraints>
+          <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="repo"/>
+        </properties>
+      </component>
     </children>
   </grid>
 </form>
index e4a4521bb89b80aacde067601743fb5df3176bca..5b4fd8ef9a53d4c69490cc452bda5a21d327cf8c 100644 (file)
@@ -18,12 +18,10 @@ package org.jetbrains.plugins.github.ui;
 import com.intellij.openapi.ui.ComboBox;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.ui.SortedComboBoxModel;
-import com.intellij.util.Consumer;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
-import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.Collection;
 import java.util.Comparator;
@@ -38,8 +36,10 @@ public class GithubCreatePullRequestPanel {
   private SortedComboBoxModel<String> myBranchModel;
   private JPanel myPanel;
   private JButton myShowDiffButton;
+  private JButton mySelectForkButton;
+  private JLabel myForkLabel;
 
-  public GithubCreatePullRequestPanel(@NotNull final Consumer<String> showDiff) {
+  public GithubCreatePullRequestPanel(@Nullable final ActionListener showDiffAction, @NotNull final ActionListener selectForkAction) {
     myDescriptionTextArea.setBorder(BorderFactory.createEtchedBorder());
     myBranchModel = new SortedComboBoxModel<String>(new Comparator<String>() {
       @Override
@@ -48,12 +48,9 @@ public class GithubCreatePullRequestPanel {
       }
     });
     myBranchComboBox.setModel(myBranchModel);
-    myShowDiffButton.addActionListener(new ActionListener() {
-      @Override
-      public void actionPerformed(ActionEvent e) {
-        showDiff.consume(getBranch());
-      }
-    });
+
+    myShowDiffButton.addActionListener(showDiffAction);
+    mySelectForkButton.addActionListener(selectForkAction);
   }
 
   @NotNull
@@ -71,21 +68,24 @@ public class GithubCreatePullRequestPanel {
     return myBranchComboBox.getSelectedItem().toString();
   }
 
+  public void setDiffEnabled(boolean enabled) {
+    myShowDiffButton.setEnabled(enabled);
+  }
+
   public void setSelectedBranch(@Nullable String branch) {
     if (StringUtil.isEmptyOrSpaces(branch)) {
-      myBranchComboBox.setSelectedItem("");
       return;
     }
 
-    if (myBranchModel.indexOf(branch) == -1) {
-      myBranchModel.add(branch);
-    }
     myBranchComboBox.setSelectedItem(branch);
   }
 
   public void setBranches(@NotNull Collection<String> branches) {
     myBranchModel.clear();
     myBranchModel.addAll(branches);
+    if (branches.size() > 0) {
+      myBranchComboBox.setSelectedIndex(0);
+    }
   }
 
   public JPanel getPanel() {
@@ -108,4 +108,8 @@ public class GithubCreatePullRequestPanel {
   public void setTitle(String title) {
     myTitleTextField.setText(title);
   }
+
+  public void setForkName(@NotNull String forkName) {
+    myForkLabel.setText(forkName);
+  }
 }
diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java
new file mode 100644 (file)
index 0000000..81d88eb
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * 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 org.jetbrains.plugins.github.ui;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.Convertor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
+import org.jetbrains.plugins.github.api.GithubFullPath;
+import org.jetbrains.plugins.github.util.GithubNotifications;
+import org.jetbrains.plugins.github.util.GithubProjectSettings;
+
+import javax.swing.*;
+import java.util.Set;
+
+/**
+ * @author Aleksey Pivovarov
+ */
+public class GithubSelectForkDialog extends DialogWrapper {
+  @NotNull private final GithubSelectForkPanel myPanel;
+  @NotNull private final Project myProject;
+  @NotNull private final Convertor<String, GithubFullPath> myCheckFork;
+  private GithubFullPath myFullPath;
+
+
+  public GithubSelectForkDialog(@NotNull Project project,
+                                @NotNull Set<GithubFullPath> forks,
+                                @NotNull Convertor<String, GithubFullPath> checkFork) {
+    super(project);
+    myProject = project;
+    myCheckFork = checkFork;
+
+    myPanel = new GithubSelectForkPanel();
+
+    myPanel.setUsers(ContainerUtil.map(forks, new Function<GithubFullPath, String>() {
+      @Override
+      public String fun(GithubFullPath path) {
+        return path.getUser();
+      }
+    }));
+
+    setTitle("Select Fork Repository");
+    init();
+  }
+
+  @Override
+  protected void doOKAction() {
+    GithubFullPath path = myCheckFork.convert(myPanel.getUser());
+    if (path == null) {
+      GithubNotifications.showErrorDialog(myProject, "Can't Create Pull Request", "Can't find repository for selected user");
+    }
+    else {
+      myFullPath = path;
+      super.doOKAction();
+    }
+  }
+
+  @Nullable
+  @Override
+  protected JComponent createCenterPanel() {
+    return myPanel.getPanel();
+  }
+
+  @NotNull
+  public GithubFullPath getPath() {
+    return myFullPath;
+  }
+
+  @TestOnly
+  public void testSetUser(@NotNull String user) {
+    myPanel.setSelectedUser(user);
+  }
+}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.form
new file mode 100644 (file)
index 0000000..84299e8
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.github.ui.GithubSelectForkPanel">
+  <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="20" y="20" width="500" height="400"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <component id="42560" class="javax.swing.JLabel">
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <text value="User:"/>
+        </properties>
+      </component>
+      <vspacer id="406">
+        <constraints>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </vspacer>
+      <component id="b3c77" class="com.intellij.openapi.ui.ComboBox" binding="myComboBox">
+        <constraints>
+          <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties>
+          <editable value="true"/>
+        </properties>
+      </component>
+    </children>
+  </grid>
+</form>
diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.java
new file mode 100644 (file)
index 0000000..754afc6
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * 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 org.jetbrains.plugins.github.ui;
+
+import com.intellij.openapi.ui.ComboBox;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.ui.SortedComboBoxModel;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.Collection;
+import java.util.Comparator;
+
+/**
+ * @author Aleksey Pivovarov
+ */
+public class GithubSelectForkPanel {
+  private final SortedComboBoxModel<String> myModel;
+  private JPanel myPanel;
+  private ComboBox myComboBox;
+
+  public GithubSelectForkPanel() {
+    myModel = new SortedComboBoxModel<String>(new Comparator<String>() {
+      @Override
+      public int compare(String o1, String o2) {
+        return StringUtil.naturalCompare(o1, o2);
+      }
+    });
+
+    myComboBox.setModel(myModel);
+  }
+
+  public void setUsers(@NotNull Collection<String> users) {
+    myModel.clear();
+    myModel.addAll(users);
+    if (users.size() > 0) {
+      myComboBox.setSelectedIndex(0);
+    }
+  }
+
+  @NotNull
+  public String getUser() {
+    return myComboBox.getSelectedItem().toString();
+  }
+
+  public void setSelectedUser(@Nullable String user) {
+    if (StringUtil.isEmptyOrSpaces(user)) {
+      return;
+    }
+
+    myComboBox.setSelectedItem(user);
+  }
+
+  public JPanel getPanel() {
+    return myPanel;
+  }
+}
index 716da7479ff8406f948893d2022a52f66aa88bc3..4b6ae29cdc69e3a8df7e9d884e11c1a464e10266 100644 (file)
@@ -19,6 +19,7 @@ import com.intellij.openapi.components.*;
 import com.intellij.openapi.project.Project;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.github.api.GithubFullPath;
 
 /**
  * @author Aleksey Pivovarov
@@ -38,8 +39,14 @@ public class GithubProjectSettings implements PersistentStateComponent<GithubPro
     myState = state;
   }
 
+  public static GithubProjectSettings getInstance(@NotNull Project project) {
+    return ServiceManager.getService(project, GithubProjectSettings.class);
+  }
+
   public static class State {
     @Nullable public String CREATE_PULL_REQUEST_DEFAULT_BRANCH = null;
+    @Nullable public String CREATE_PULL_REQUEST_DEFAULT_REPO_USER = null;
+    @Nullable public String CREATE_PULL_REQUEST_DEFAULT_REPO_NAME = null;
   }
 
   @Nullable
@@ -51,7 +58,16 @@ public class GithubProjectSettings implements PersistentStateComponent<GithubPro
     myState.CREATE_PULL_REQUEST_DEFAULT_BRANCH = branch;
   }
 
-  public static GithubProjectSettings getInstance(@NotNull Project project) {
-    return ServiceManager.getService(project, GithubProjectSettings.class);
+  @Nullable
+  public GithubFullPath getCreatePullRequestDefaultRepo() {
+    if (myState.CREATE_PULL_REQUEST_DEFAULT_REPO_USER == null || myState.CREATE_PULL_REQUEST_DEFAULT_REPO_NAME == null) {
+      return null;
+    }
+    return new GithubFullPath(myState.CREATE_PULL_REQUEST_DEFAULT_REPO_USER, myState.CREATE_PULL_REQUEST_DEFAULT_REPO_NAME);
+  }
+
+  public void setCreatePullRequestDefaultRepo(@NotNull GithubFullPath repo) {
+    myState.CREATE_PULL_REQUEST_DEFAULT_REPO_USER = repo.getUser();
+    myState.CREATE_PULL_REQUEST_DEFAULT_REPO_NAME = repo.getRepository();
   }
 }
index e5659d8e109f42be2bd6d89f751ad99eb9fbe727..354dddb866a0f01a8024271b1374ef2454961be2 100644 (file)
@@ -22,7 +22,7 @@ import com.intellij.notification.NotificationType;
  */
 public class GithubCreatePullRequestTest extends GithubCreatePullRequestTestBase {
   public void testSimple() throws Exception {
-    registerDefaultCreatePullRequestDialogHandler(myLogin1 + ":master");
+    registerDefaultCreatePullRequestDialogHandler("master", myLogin1);
 
     GithubCreatePullRequestAction.createPullRequest(myProject, myProjectRoot);
 
@@ -32,17 +32,8 @@ public class GithubCreatePullRequestTest extends GithubCreatePullRequestTestBase
   }
 
   public void testParent() throws Exception {
-    registerDefaultCreatePullRequestDialogHandler(myLogin2 + ":file2");
-
-    GithubCreatePullRequestAction.createPullRequest(myProject, myProjectRoot);
-
-    checkNotification(NotificationType.INFORMATION, "Successfully created pull request", null);
-    checkRemoteConfigured();
-    checkLastCommitPushed();
-  }
-
-  public void testCommitRef1() throws Exception {
-    registerDefaultCreatePullRequestDialogHandler(myLogin1 + ":refs/heads/master");
+    registerDefaultCreatePullRequestDialogHandler("file2", myLogin2);
+    addRemote(myLogin2);
 
     GithubCreatePullRequestAction.createPullRequest(myProject, myProjectRoot);
 
index 9db5ba8a0b1da8f428e97a4fc96621b8bd30f51e..741ccd6e08f4c6fc2bce777bcb458e4902386e29 100644 (file)
@@ -24,8 +24,11 @@ import git4idea.actions.GitInit;
 import git4idea.commands.Git;
 import git4idea.repo.GitRepository;
 import git4idea.test.TestDialogHandler;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.github.api.GithubFullPath;
 import org.jetbrains.plugins.github.test.GithubTest;
 import org.jetbrains.plugins.github.ui.GithubCreatePullRequestDialog;
+import org.jetbrains.plugins.github.util.GithubUrlUtil;
 import org.jetbrains.plugins.github.util.GithubUtil;
 
 import java.util.Random;
@@ -38,6 +41,7 @@ import static git4idea.test.GitExecutor.git;
  */
 public abstract class GithubCreatePullRequestTestBase extends GithubTest {
   protected static final String PROJECT_URL = "https://github.com/ideatest1/PullRequestTest";
+  protected static final String PROJECT_NAME = "PullRequestTest";
   protected String BRANCH_NAME;
 
   @Override
@@ -67,12 +71,14 @@ public abstract class GithubCreatePullRequestTestBase extends GithubTest {
     }
   }
 
-  protected void registerDefaultCreatePullRequestDialogHandler(final String branch) {
+  protected void registerDefaultCreatePullRequestDialogHandler(@NotNull final String branch, @NotNull final String user) {
     myDialogManager.registerDialogHandler(GithubCreatePullRequestDialog.class, new TestDialogHandler<GithubCreatePullRequestDialog>() {
       @Override
       public int handleDialog(GithubCreatePullRequestDialog dialog) {
-        dialog.setRequestTitle(BRANCH_NAME);
-        dialog.setBranch(branch);
+        dialog.testSetRequestTitle(BRANCH_NAME);
+        dialog.testSetBranch(branch);
+        dialog.testSetTarget(new GithubFullPath(user, PROJECT_NAME));
+        dialog.testCreatePullRequest();
         return DialogWrapper.OK_EXIT_CODE;
       }
     });
@@ -84,6 +90,10 @@ public abstract class GithubCreatePullRequestTestBase extends GithubTest {
     GitInit.refreshAndConfigureVcsMappings(myProject, myProjectRoot, myProjectRoot.getPath());
   }
 
+  protected void addRemote(@NotNull String user) {
+    git("remote add somename " + GithubUrlUtil.getCloneUrl(new GithubFullPath(user, PROJECT_NAME)));
+  }
+
   protected void createBranch() {
     git("branch " + BRANCH_NAME);
     git("checkout " + BRANCH_NAME);