From 9e728e388b1e0905b523199a7144675607e378ff Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 23 Sep 2013 13:52:54 +0400 Subject: [PATCH 01/32] Github: rewrite CreatePullRequestAction * split doalog window onto two: - select target repository - select target branch | show diff | create PR * fetch remote only once * do not allow custom target refs (ex: tags, hash) Changing target repository seems to be very rare operation, and it's nice to reduce complexity of main window. --- .../github/GithubCreatePullRequestAction.java | 607 ++++++++---------- .../plugins/github/api/GithubFullPath.java | 2 +- .../ui/GithubCreatePullRequestDialog.java | 26 +- .../ui/GithubCreatePullRequestPanel.form | 42 +- .../ui/GithubCreatePullRequestPanel.java | 31 +- .../github/ui/GithubSelectForkDialog.java | 91 +++ .../github/ui/GithubSelectForkPanel.form | 34 + .../github/ui/GithubSelectForkPanel.java | 71 ++ .../github/util/GithubProjectSettings.java | 20 +- .../github/GithubCreatePullRequestTest.java | 17 +- .../GithubCreatePullRequestTestBase.java | 13 + 11 files changed, 564 insertions(+), 390 deletions(-) create mode 100644 plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java create mode 100644 plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.form create mode 100644 plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.java diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java index 8c0ff6bf621f..216aa955d405 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java @@ -34,15 +34,11 @@ 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 com.intellij.util.containers.*; 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; @@ -59,13 +55,12 @@ 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 org.jetbrains.plugins.github.ui.GithubSelectForkDialog; +import org.jetbrains.plugins.github.util.*; import java.io.IOException; import java.util.*; +import java.util.HashSet; import java.util.concurrent.atomic.AtomicReference; import static org.jetbrains.plugins.github.util.GithubUtil.setVisibleEnabled; @@ -117,64 +112,71 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { static void createPullRequest(@NotNull final Project project, @Nullable final VirtualFile file) { final Git git = ServiceManager.getService(Git.class); + final GithubProjectSettings projectSettings = GithubProjectSettings.getInstance(project); - final GitRepository repository = GithubUtil.getGitRepository(project, file); - if (repository == null) { + final GitRepository gitRepository = GithubUtil.getGitRepository(project, file); + if (gitRepository == null) { GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find git repository"); return; } - repository.update(); + gitRepository.update(); - Pair remote = GithubUtil.findGithubRemote(repository); + Pair remote = GithubUtil.findGithubRemote(gitRepository); 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) { + final String remoteUrl = remote.getSecond(); + final GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl); + if (path == null) { GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't process remote: " + remoteUrl); return; } - final GitLocalBranch currentBranch = repository.getCurrentBranch(); + final GitLocalBranch currentBranch = gitRepository.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); + GithubFullPath forkPath = projectSettings.getCreatePullRequestDefaultRepo(); + if (forkPath == null) { + openSelectTargetForkDialog(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch.getName()); + return; + } - final Map forks = new HashMap(); - final Set branches = new HashSet(); - addAvailableBranchesFromGit(repository, forks, branches); - GithubInfo info = loadGithubInfoAndBranchesWithModal(project, userAndRepo, upstreamUserAndRepo, forks, branches); + performCreatePullRequest(project, git, gitRepository, path, forkPath, remoteName, remoteUrl, currentBranch.getName()); + } + + private static void performCreatePullRequest(@NotNull final Project project, + @NotNull final Git git, + @NotNull final GitRepository gitRepository, + @NotNull final GithubFullPath path, + @NotNull final GithubFullPath forkPath, + @NotNull final String remoteName, + @NotNull final String remoteUrl, + @NotNull final String currentBranch) { + final GithubInfo info = prepareInfoWithModal(project, forkPath, gitRepository); 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 suggestions = ContainerUtil.map(branches, new Function() { + Consumer showDiff = info.getTargetRemote() != null ? new Consumer() { @Override - public String fun(RemoteBranch remoteBranch) { - return remoteBranch.getReference(); + public void consume(String branch) { + showDiffByRef(project, branch, gitRepository, info.getTargetRemote(), currentBranch); } - }); - Consumer showDiff = new Consumer() { + } : null; + Runnable showSelectForkDialog = new Runnable() { @Override - public void consume(String ref) { - showDiffByRef(project, ref, repository, currentBranch.getName(), auth, forks, branches, repo.getSource()); + public void run() { + openSelectTargetForkDialog(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch); } }; - final GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(project, suggestions, defaultBranch, showDiff); + final GithubCreatePullRequestDialog dialog = + new GithubCreatePullRequestDialog(project, forkPath.getFullName(), info.getBranches(), showDiff, showSelectForkDialog); DialogManager.show(dialog); if (!dialog.isOK()) { return; @@ -185,26 +187,19 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { 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); + GitCommandResult result = git.push(gitRepository, remoteName, remoteUrl, currentBranch, true); if (!result.success()) { GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Push failed:
" + result.getErrorOutputAsHtmlString()); return; } - String from = repo.getUserName() + ":" + currentBranch.getName(); + String from = path.getUser() + ":" + currentBranch; 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); + createPullRequest(project, auth, forkPath, dialog.getRequestTitle(), dialog.getDescription(), from, onto); if (request == null) { return; } @@ -216,26 +211,58 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { } @Nullable - private static GithubInfo loadGithubInfoAndBranchesWithModal(@NotNull final Project project, - @NotNull final GithubFullPath userAndRepo, - @Nullable final GithubFullPath upstreamUserAndRepo, - @NotNull final Map forks, - @NotNull final Set branches) { + private static GithubInfo prepareInfoWithModal(@NotNull final Project project, + @NotNull final GithubFullPath forkPath, + @NotNull final GitRepository gitRepository) { try { return GithubUtil .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor() { @Override public GithubInfo convert(ProgressIndicator indicator) throws IOException { - final AtomicReference reposRef = new AtomicReference(); + // configure remote + GitRemote targetRemote = GithubUtil.findGithubRemote(gitRepository, forkPath); + String targetRemoteName = targetRemote == null ? null : targetRemote.getName(); + if (targetRemoteName == null) { + final AtomicReference responseRef = new AtomicReference(); + ApplicationManager.getApplication().invokeAndWait(new Runnable() { + @Override + public void run() { + responseRef.set(GithubNotifications + .showYesNoDialog(project, "Can't find remote", "Configure remote for '" + forkPath.getUser() + "'?")); + } + }, indicator.getModalityState()); + if (responseRef.get() == Messages.YES) { + targetRemoteName = configureRemote(project, gitRepository, forkPath); + } + } + + // load available branches + final AtomicReference> reposRef = new AtomicReference>(); final GithubAuthData auth = GithubUtil.runAndGetValidAuth(project, indicator, new ThrowableConsumer() { @Override public void consume(GithubAuthData authData) throws IOException { - reposRef.set(GithubApiUtil.getDetailedRepoInfo(authData, userAndRepo.getUser(), userAndRepo.getRepository())); + reposRef.set(ContainerUtil.map(GithubApiUtil.getRepoBranches(authData, forkPath.getUser(), forkPath.getRepository()), + new Function() { + @Override + public String fun(GithubBranch githubBranch) { + return githubBranch.getName(); + } + })); } }); - addAvailableBranchesFromGithub(project, auth, reposRef.get(), upstreamUserAndRepo, forks, branches); - return new GithubInfo(auth, reposRef.get()); + + + // fetch + if (targetRemoteName != null) { + GitFetchResult result = new GitFetcher(project, indicator, false).fetch(gitRepository.getRoot(), targetRemoteName, null); + if (!result.isSuccess()) { + GitFetcher.displayFetchResult(project, result, null, result.getErrors()); + targetRemoteName = null; + } + } + + return new GithubInfo(auth, reposRef.get(), targetRemoteName); } }); } @@ -249,42 +276,15 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { } @Nullable - private static GithubFullPath findRepositoryByUser(@NotNull Project project, - @NotNull String user, - @NotNull Map forks, - @NotNull GithubAuthData auth, - @Nullable GithubRepo source) { - for (Map.Entry entry : forks.entrySet()) { - if (StringUtil.equalsIgnoreCase(user, entry.getKey())) { - return new GithubFullPath(entry.getKey(), entry.getValue()); - } + 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(); } - - 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); - } + else { + return null; } - - return null; } @Nullable @@ -304,91 +304,12 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { } } - private static void addAvailableBranchesFromGit(@NotNull GitRepository gitRepository, - @NotNull Map forks, - @NotNull Set 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 forks, - @NotNull Set 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 getBranches(@NotNull GithubAuthData auth, @NotNull final String user, @NotNull final String repo) - throws IOException { - List branches = GithubApiUtil.getRepoBranches(auth, user, repo); - return ContainerUtil.map(branches, new Function() { - @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, + @Nullable final String branch, @NotNull final GitRepository gitRepository, - @NotNull final String currentBranch, - @NotNull final GithubAuthData auth, - @NotNull final Map forks, - @NotNull final Set branches, - @Nullable final GithubRepo source) { - if (ref == null) { + @NotNull final String targetRemote, + @NotNull final String currentBranch) { + if (branch == null) { return; } @@ -396,69 +317,11 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { @Override @Nullable public DiffInfo convert(ProgressIndicator indicator) { - List 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 responseRef = new AtomicReference(); - 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; + return getDiffInfo(project, gitRepository, currentBranch, targetRemote + "/" + branch); } }); if (info == null) { + GithubNotifications.showErrorDialog(project, "Can't show diff", "Can't get diff info"); return; } @@ -466,45 +329,6 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { 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 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, @@ -524,81 +348,193 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { } } - 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); + private static void openSelectTargetForkDialog(@NotNull final Project project, + @NotNull final Git git, + @NotNull final GitRepository gitRepository, + @NotNull final GithubFullPath path, + @NotNull final String remoteName, + @NotNull final String remoteUrl, + @NotNull final String currentBranch) { + final GithubInfo2 info = getAvailableForksInModal(project, gitRepository, path); + if (info == null) { + return; } - public RemoteBranch(@NotNull String user, @NotNull String branch, @Nullable GitRemoteBranch localBranch) { - myUser = user; - myBranch = branch; - myRemoteBranch = localBranch; + Convertor getForkPath = new Convertor() { + @Nullable + @Override + public GithubFullPath convert(final String user) { + return GithubUtil.computeValueInModal(project, "Access to GitHub", new Convertor() { + @Nullable + @Override + public GithubFullPath convert(ProgressIndicator o) { + return findRepositoryByUser(project, user, info.getForks(), info.getAuthData(), info.getSource()); + } + }); + } + }; + GithubSelectForkDialog dialog = new GithubSelectForkDialog(project, info.getForks(), getForkPath); + dialog.show(); + if (!dialog.isOK()) { + return; } - @NotNull - public String getReference() { - return myUser + ":" + myBranch; + performCreatePullRequest(project, git, gitRepository, path, dialog.getPath(), remoteName, remoteUrl, currentBranch); + } + + @Nullable + private static GithubInfo2 getAvailableForksInModal(@NotNull final Project project, + @NotNull final GitRepository gitRepository, + @NotNull final GithubFullPath path) { + return GithubUtil.computeValueInModal(project, "Access to GitHub", new Convertor() { + @Nullable + @Override + public GithubInfo2 convert(ProgressIndicator indicator) { + try { + final Set forks = new HashSet(); + + // GitHub + final AtomicReference sourceRef = new AtomicReference(); + GithubAuthData authData = GithubUtil.runAndGetValidAuth(project, indicator, new ThrowableConsumer() { + @Override + public void consume(GithubAuthData authData) throws IOException { + GithubRepoDetailed repo = GithubApiUtil.getDetailedRepoInfo(authData, 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()); + } + if (repo.getSource() != null) { + sourceRef.set(repo.getSource()); + } + else { + sourceRef.set(repo); + } + } + }); + + // Git + forks.addAll(getAvailableForksFromGit(gitRepository)); + + return new GithubInfo2(forks, authData, sourceRef.get()); + } + catch (GithubAuthenticationCanceledException e) { + return null; + } + catch (IOException e) { + GithubNotifications.showErrorDialog(project, CANNOT_CREATE_PULL_REQUEST, e); + return null; + } + } + }); + } + + @NotNull + private static List getAvailableForksFromGit(@NotNull GitRepository gitRepository) { + List forks = new ArrayList(); + 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 forks, + @NotNull GithubAuthData auth, + @NotNull GithubRepo source) { + for (GithubFullPath path : forks) { + if (StringUtil.equalsIgnoreCase(user, path.getUser())) { + return path; + } } - @NotNull - public String getUser() { - return myUser; + 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 } - @NotNull - public String getBranch() { - return myBranch; + 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); } - @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; - } + return null; } private static class GithubInfo { - @NotNull private final GithubRepoDetailed myRepo; + @NotNull private final List myBranches; @NotNull private final GithubAuthData myAuthData; + @Nullable private final String myTargetRemote; - private GithubInfo(@NotNull GithubAuthData authData, @NotNull GithubRepoDetailed repo) { + private GithubInfo(@NotNull GithubAuthData authData, @NotNull List repo, @Nullable String targetRemote) { myAuthData = authData; - myRepo = repo; + myBranches = repo; + myTargetRemote = targetRemote; } @NotNull - public GithubRepoDetailed getRepo() { - return myRepo; + public List getBranches() { + return myBranches; } @NotNull public GithubAuthData getAuthData() { return myAuthData; } + + @Nullable + public String getTargetRemote() { + return myTargetRemote; + } + } + + private static class GithubInfo2 { + @NotNull private final Set myForks; + @NotNull private final GithubAuthData myAuthData; + @NotNull private final GithubRepo mySource; + + private GithubInfo2(@NotNull Set forks, @NotNull GithubAuthData authData, @NotNull GithubRepo source) { + myForks = forks; + myAuthData = authData; + mySource = source; + } + + @NotNull + public Set getForks() { + return myForks; + } + + @NotNull + public GithubAuthData getAuthData() { + return myAuthData; + } + + @NotNull + public GithubRepo getSource() { + return mySource; + } } private static class DiffInfo { @@ -627,31 +563,4 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { 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; - } - } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubFullPath.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubFullPath.java index c2c7c7f63d86..740d34a2837f 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubFullPath.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubFullPath.java @@ -41,7 +41,7 @@ public class GithubFullPath { } @NotNull - public String toString() { + public String getFullName() { return myUserName + '/' + myRepositoryName; } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index e0c648e16568..30673bfa0a48 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -37,18 +37,28 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { @NotNull private static final Pattern GITHUB_REPO_PATTERN = Pattern.compile("[a-zA-Z0-9_.-]+:[a-zA-Z0-9_.-]+"); @NotNull private final Project myProject; - public GithubCreatePullRequestDialog(@NotNull final Project project, + public GithubCreatePullRequestDialog(@NotNull Project project, + @NotNull String repoName, @NotNull Collection branches, - @Nullable String suggestedBranch, - @NotNull Consumer showDiff) { + @Nullable Consumer showDiff, + @NotNull final Runnable showSelectForkDialog) { super(project, true); - myGithubCreatePullRequestPanel = new GithubCreatePullRequestPanel(showDiff); + myProject = project; + + myGithubCreatePullRequestPanel = new GithubCreatePullRequestPanel(showDiff, new Runnable() { + @Override + public void run() { + doCancelAction(); + showSelectForkDialog.run(); + } + }); myGithubCreatePullRequestPanel.setBranches(branches); - myProject = project; String configBranch = GithubProjectSettings.getInstance(myProject).getCreatePullRequestDefaultBranch(); - myGithubCreatePullRequestPanel.setSelectedBranch(configBranch != null ? configBranch : suggestedBranch); + if (configBranch != null) myGithubCreatePullRequestPanel.setSelectedBranch(configBranch); + + myGithubCreatePullRequestPanel.setForkName(repoName); setTitle("Create Pull Request"); init(); @@ -104,10 +114,6 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { 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; } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form index 46864f055405..b468a0b585ab 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form @@ -1,6 +1,6 @@
- + @@ -10,7 +10,7 @@ - + @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -42,16 +42,16 @@ - + - + - + @@ -66,12 +66,36 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java index e4a4521bb89b..5eec711ee071 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java @@ -38,8 +38,10 @@ public class GithubCreatePullRequestPanel { private SortedComboBoxModel myBranchModel; private JPanel myPanel; private JButton myShowDiffButton; + private JButton mySelectForkButton; + private JLabel myForkLabel; - public GithubCreatePullRequestPanel(@NotNull final Consumer showDiff) { + public GithubCreatePullRequestPanel(@Nullable final Consumer showDiff, @NotNull final Runnable showSelectForkDialog) { myDescriptionTextArea.setBorder(BorderFactory.createEtchedBorder()); myBranchModel = new SortedComboBoxModel(new Comparator() { @Override @@ -48,10 +50,22 @@ public class GithubCreatePullRequestPanel { } }); myBranchComboBox.setModel(myBranchModel); - myShowDiffButton.addActionListener(new ActionListener() { + + if (showDiff != null) { + myShowDiffButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showDiff.consume(getBranch()); + } + }); + } + else { + myShowDiffButton.setEnabled(false); + } + mySelectForkButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - showDiff.consume(getBranch()); + showSelectForkDialog.run(); } }); } @@ -73,19 +87,18 @@ public class GithubCreatePullRequestPanel { 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 branches) { myBranchModel.clear(); myBranchModel.addAll(branches); + if (branches.size() > 0) { + myBranchComboBox.setSelectedIndex(0); + } } public JPanel getPanel() { @@ -108,4 +121,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 index 000000000000..7e42b52b4af5 --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java @@ -0,0 +1,91 @@ +/* + * 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 myCheckFork; + private GithubFullPath myFullPath; + + + public GithubSelectForkDialog(@NotNull Project project, + @NotNull Set forks, + @NotNull Convertor checkFork) { + super(project); + myProject = project; + myCheckFork = checkFork; + + myPanel = new GithubSelectForkPanel(); + + myPanel.setUsers(ContainerUtil.map(forks, new Function() { + @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; + GithubProjectSettings.getInstance(myProject).setCreatePullRequestDefaultRepo(path); + super.doOKAction(); + } + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + return myPanel.getPanel(); + } + + @NotNull + public GithubFullPath getPath() { + return myFullPath; + } + + @TestOnly + public void setUser(@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 index 000000000000..84299e815dc5 --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.form @@ -0,0 +1,34 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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 index 000000000000..754afc617057 --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.java @@ -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 myModel; + private JPanel myPanel; + private ComboBox myComboBox; + + public GithubSelectForkPanel() { + myModel = new SortedComboBoxModel(new Comparator() { + @Override + public int compare(String o1, String o2) { + return StringUtil.naturalCompare(o1, o2); + } + }); + + myComboBox.setModel(myModel); + } + + public void setUsers(@NotNull Collection 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; + } +} diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubProjectSettings.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubProjectSettings.java index 716da7479ff8..4b6ae29cdc69 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubProjectSettings.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubProjectSettings.java @@ -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 Date: Sat, 28 Sep 2013 20:50:12 +0400 Subject: [PATCH 02/32] Github: rewrite CreatePullRequest: Part2 * do not recreate window on changing target fork --- .../github/GithubCreatePullRequestAction.java | 491 +--------------- .../github/GithubCreatePullRequestWorker.java | 529 ++++++++++++++++++ .../ui/GithubCreatePullRequestDialog.java | 85 ++- .../ui/GithubCreatePullRequestPanel.java | 27 +- 4 files changed, 606 insertions(+), 526 deletions(-) create mode 100644 plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java index 216aa955d405..82a68ba54ea3 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java @@ -17,61 +17,25 @@ package org.jetbrains.plugins.github; import com.intellij.openapi.actionSystem.AnActionEvent; 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.*; 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 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.ui.GithubSelectForkDialog; import org.jetbrains.plugins.github.util.*; -import java.io.IOException; -import java.util.*; -import java.util.HashSet; -import java.util.concurrent.atomic.AtomicReference; - +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); } @@ -110,457 +74,16 @@ 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); + static void createPullRequest(@NotNull Project project, @Nullable VirtualFile file) { final GithubProjectSettings projectSettings = GithubProjectSettings.getInstance(project); - - final GitRepository gitRepository = GithubUtil.getGitRepository(project, file); - if (gitRepository == null) { - GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find git repository"); - return; - } - gitRepository.update(); - - Pair remote = GithubUtil.findGithubRemote(gitRepository); - if (remote == null) { - GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find GitHub remote"); - return; - } - final String remoteName = remote.getFirst().getName(); - final String remoteUrl = remote.getSecond(); - final GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl); - if (path == null) { - GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't process remote: " + remoteUrl); - return; - } - - final GitLocalBranch currentBranch = gitRepository.getCurrentBranch(); - if (currentBranch == null) { - GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "No current branch"); - return; - } - GithubFullPath forkPath = projectSettings.getCreatePullRequestDefaultRepo(); - if (forkPath == null) { - openSelectTargetForkDialog(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch.getName()); + + GithubCreatePullRequestWorker worker = createPullRequestWorker(project, file); + if (worker == null) { return; } - performCreatePullRequest(project, git, gitRepository, path, forkPath, remoteName, remoteUrl, currentBranch.getName()); - } - - private static void performCreatePullRequest(@NotNull final Project project, - @NotNull final Git git, - @NotNull final GitRepository gitRepository, - @NotNull final GithubFullPath path, - @NotNull final GithubFullPath forkPath, - @NotNull final String remoteName, - @NotNull final String remoteUrl, - @NotNull final String currentBranch) { - final GithubInfo info = prepareInfoWithModal(project, forkPath, gitRepository); - if (info == null) { - return; - } - final GithubAuthData auth = info.getAuthData(); - - Consumer showDiff = info.getTargetRemote() != null ? new Consumer() { - @Override - public void consume(String branch) { - showDiffByRef(project, branch, gitRepository, info.getTargetRemote(), currentBranch); - } - } : null; - Runnable showSelectForkDialog = new Runnable() { - @Override - public void run() { - openSelectTargetForkDialog(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch); - } - }; - final GithubCreatePullRequestDialog dialog = - new GithubCreatePullRequestDialog(project, forkPath.getFullName(), info.getBranches(), showDiff, showSelectForkDialog); + GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(worker, forkPath); 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(gitRepository, remoteName, remoteUrl, currentBranch, true); - if (!result.success()) { - GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Push failed:
" + result.getErrorOutputAsHtmlString()); - return; - } - - String from = path.getUser() + ":" + currentBranch; - String onto = dialog.getTargetBranch(); - - LOG.info("Creating pull request"); - indicator.setText("Creating pull request..."); - GithubPullRequest request = - createPullRequest(project, auth, forkPath, 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 prepareInfoWithModal(@NotNull final Project project, - @NotNull final GithubFullPath forkPath, - @NotNull final GitRepository gitRepository) { - try { - return GithubUtil - .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor() { - @Override - public GithubInfo convert(ProgressIndicator indicator) throws IOException { - // configure remote - GitRemote targetRemote = GithubUtil.findGithubRemote(gitRepository, forkPath); - String targetRemoteName = targetRemote == null ? null : targetRemote.getName(); - if (targetRemoteName == null) { - final AtomicReference responseRef = new AtomicReference(); - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - @Override - public void run() { - responseRef.set(GithubNotifications - .showYesNoDialog(project, "Can't find remote", "Configure remote for '" + forkPath.getUser() + "'?")); - } - }, indicator.getModalityState()); - if (responseRef.get() == Messages.YES) { - targetRemoteName = configureRemote(project, gitRepository, forkPath); - } - } - - // load available branches - final AtomicReference> reposRef = new AtomicReference>(); - final GithubAuthData auth = - GithubUtil.runAndGetValidAuth(project, indicator, new ThrowableConsumer() { - @Override - public void consume(GithubAuthData authData) throws IOException { - reposRef.set(ContainerUtil.map(GithubApiUtil.getRepoBranches(authData, forkPath.getUser(), forkPath.getRepository()), - new Function() { - @Override - public String fun(GithubBranch githubBranch) { - return githubBranch.getName(); - } - })); - } - }); - - - // fetch - if (targetRemoteName != null) { - GitFetchResult result = new GitFetcher(project, indicator, false).fetch(gitRepository.getRoot(), targetRemoteName, null); - if (!result.isSuccess()) { - GitFetcher.displayFetchResult(project, result, null, result.getErrors()); - targetRemoteName = null; - } - } - - return new GithubInfo(auth, reposRef.get(), targetRemoteName); - } - }); - } - catch (GithubAuthenticationCanceledException e) { - return null; - } - catch (IOException e) { - GithubNotifications.showErrorDialog(project, CANNOT_CREATE_PULL_REQUEST, e); - return null; - } - } - - @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 targetRemote, - @NotNull final String currentBranch) { - if (branch == null) { - return; - } - - DiffInfo info = GithubUtil.computeValueInModal(project, "Collecting diff data...", new Convertor() { - @Override - @Nullable - public DiffInfo convert(ProgressIndicator indicator) { - return getDiffInfo(project, gitRepository, currentBranch, targetRemote + "/" + 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 commits = GitHistoryUtils.history(project, repository.getRoot(), targetBranch + ".."); - Collection 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>create(new ArrayList(), commits)); - return new DiffInfo(info, currentBranch, targetBranch); - } - catch (VcsException e) { - LOG.info(e); - return null; - } - } - - private static void openSelectTargetForkDialog(@NotNull final Project project, - @NotNull final Git git, - @NotNull final GitRepository gitRepository, - @NotNull final GithubFullPath path, - @NotNull final String remoteName, - @NotNull final String remoteUrl, - @NotNull final String currentBranch) { - final GithubInfo2 info = getAvailableForksInModal(project, gitRepository, path); - if (info == null) { - return; - } - - Convertor getForkPath = new Convertor() { - @Nullable - @Override - public GithubFullPath convert(final String user) { - return GithubUtil.computeValueInModal(project, "Access to GitHub", new Convertor() { - @Nullable - @Override - public GithubFullPath convert(ProgressIndicator o) { - return findRepositoryByUser(project, user, info.getForks(), info.getAuthData(), info.getSource()); - } - }); - } - }; - GithubSelectForkDialog dialog = new GithubSelectForkDialog(project, info.getForks(), getForkPath); - dialog.show(); - if (!dialog.isOK()) { - return; - } - - performCreatePullRequest(project, git, gitRepository, path, dialog.getPath(), remoteName, remoteUrl, currentBranch); - } - - @Nullable - private static GithubInfo2 getAvailableForksInModal(@NotNull final Project project, - @NotNull final GitRepository gitRepository, - @NotNull final GithubFullPath path) { - return GithubUtil.computeValueInModal(project, "Access to GitHub", new Convertor() { - @Nullable - @Override - public GithubInfo2 convert(ProgressIndicator indicator) { - try { - final Set forks = new HashSet(); - - // GitHub - final AtomicReference sourceRef = new AtomicReference(); - GithubAuthData authData = GithubUtil.runAndGetValidAuth(project, indicator, new ThrowableConsumer() { - @Override - public void consume(GithubAuthData authData) throws IOException { - GithubRepoDetailed repo = GithubApiUtil.getDetailedRepoInfo(authData, 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()); - } - if (repo.getSource() != null) { - sourceRef.set(repo.getSource()); - } - else { - sourceRef.set(repo); - } - } - }); - - // Git - forks.addAll(getAvailableForksFromGit(gitRepository)); - - return new GithubInfo2(forks, authData, sourceRef.get()); - } - catch (GithubAuthenticationCanceledException e) { - return null; - } - catch (IOException e) { - GithubNotifications.showErrorDialog(project, CANNOT_CREATE_PULL_REQUEST, e); - return null; - } - } - }); - } - - @NotNull - private static List getAvailableForksFromGit(@NotNull GitRepository gitRepository) { - List forks = new ArrayList(); - 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 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 myBranches; - @NotNull private final GithubAuthData myAuthData; - @Nullable private final String myTargetRemote; - - private GithubInfo(@NotNull GithubAuthData authData, @NotNull List repo, @Nullable String targetRemote) { - myAuthData = authData; - myBranches = repo; - myTargetRemote = targetRemote; - } - - @NotNull - public List getBranches() { - return myBranches; - } - - @NotNull - public GithubAuthData getAuthData() { - return myAuthData; - } - - @Nullable - public String getTargetRemote() { - return myTargetRemote; - } - } - - private static class GithubInfo2 { - @NotNull private final Set myForks; - @NotNull private final GithubAuthData myAuthData; - @NotNull private final GithubRepo mySource; - - private GithubInfo2(@NotNull Set forks, @NotNull GithubAuthData authData, @NotNull GithubRepo source) { - myForks = forks; - myAuthData = authData; - mySource = source; - } - - @NotNull - public Set getForks() { - return myForks; - } - - @NotNull - public GithubAuthData getAuthData() { - return myAuthData; - } - - @NotNull - public GithubRepo getSource() { - return mySource; - } - } - - 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; - } - } -} +} \ 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 index 000000000000..67a88990454f --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -0,0 +1,529 @@ +package org.jetbrains.plugins.github; + +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.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.ThrowableConsumer; +import com.intellij.util.ThrowableConvertor; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Convertor; +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; + + private volatile 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) { + myProject = project; + myGit = git; + myGitRepository = gitRepository; + myPath = path; + myRemoteName = remoteName; + myRemoteUrl = remoteUrl; + myCurrentBranch = currentBranch; + } + + @NotNull + public Project getProject() { + return myProject; + } + + @Nullable + public static GithubCreatePullRequestWorker createPullRequestWorker(@NotNull final Project project, @Nullable final VirtualFile file) { + final Git git = ServiceManager.getService(Git.class); + + final 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 remote = GithubUtil.findGithubRemote(gitRepository); + if (remote == null) { + GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find GitHub remote"); + return null; + } + final String remoteName = remote.getFirst().getName(); + final String remoteUrl = remote.getSecond(); + final GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl); + if (path == null) { + GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't process remote: " + remoteUrl); + return null; + } + + final GitLocalBranch currentBranch = gitRepository.getCurrentBranch(); + if (currentBranch == null) { + GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "No current branch"); + return null; + } + + return new GithubCreatePullRequestWorker(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch.getName()); + } + + @Nullable + public Collection setTarget(@NotNull final GithubFullPath forkPath) { + try { + GithubInfo info = + GithubUtil.computeValueInModal(myProject, "Access to GitHub", new ThrowableConvertor() { + @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 responseRef = new AtomicReference(); + 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 + final AtomicReference> reposRef = new AtomicReference>(); + final GithubAuthData auth = + runAndGetValidAuthIfNeeded(myProject, myAuth, indicator, new ThrowableConsumer() { + @Override + public void consume(GithubAuthData authData) throws IOException { + reposRef.set(ContainerUtil.map(GithubApiUtil.getRepoBranches(authData, forkPath.getUser(), forkPath.getRepository()), + new Function() { + @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(auth, reposRef.get(), targetRemoteName); + } + }); + + myAuth = info.getAuthData(); + myForkPath = forkPath; + myTargetRemote = info.getTargetRemote(); + return info.getBranches(); + } + 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; + } + myAuth = info.getAuthData(); + + Convertor getForkPath = new Convertor() { + @Nullable + @Override + public GithubFullPath convert(@NotNull final String user) { + return GithubUtil.computeValueInModal(myProject, "Access to GitHub", new Convertor() { + @Nullable + @Override + public GithubFullPath convert(ProgressIndicator o) { + return findRepositoryByUser(myProject, user, info.getForks(), myAuth, info.getSource()); + } + }); + } + }; + GithubSelectForkDialog dialog = new GithubSelectForkDialog(myProject, info.getForks(), getForkPath); + dialog.show(); + 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) { + if (myAuth == null) { + try { + myAuth = GithubUtil.getValidAuthData(myProject, indicator); + } + catch (GithubAuthenticationCanceledException e) { + return; + } + } + + 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:
" + 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 targetRemote, + @NotNull final String currentBranch) { + if (branch == null) { + return; + } + + DiffInfo info = GithubUtil.computeValueInModal(project, "Collecting diff data...", new Convertor() { + @Override + @Nullable + public DiffInfo convert(ProgressIndicator indicator) { + return getDiffInfo(project, gitRepository, currentBranch, targetRemote + "/" + 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 commits = GitHistoryUtils.history(project, repository.getRoot(), targetBranch + ".."); + Collection 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>create(new ArrayList(), 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, + @Nullable final GithubAuthData auth, + @NotNull final GithubFullPath path) { + return GithubUtil.computeValueInModal(project, "Access to GitHub", new Convertor() { + @Nullable + @Override + public GithubInfo2 convert(ProgressIndicator indicator) { + try { + final Set forks = new HashSet(); + + // GitHub + final AtomicReference sourceRef = new AtomicReference(); + GithubAuthData authData = + runAndGetValidAuthIfNeeded(project, auth, indicator, new ThrowableConsumer() { + @Override + public void consume(GithubAuthData authData) throws IOException { + GithubRepoDetailed repo = GithubApiUtil.getDetailedRepoInfo(authData, 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()); + } + if (repo.getSource() != null) { + sourceRef.set(repo.getSource()); + } + else { + sourceRef.set(repo); + } + } + }); + + // Git + forks.addAll(getAvailableForksFromGit(gitRepository)); + + return new GithubInfo2(forks, authData, sourceRef.get()); + } + catch (GithubAuthenticationCanceledException e) { + return null; + } + catch (IOException e) { + GithubNotifications.showErrorDialog(project, CANNOT_CREATE_PULL_REQUEST, e); + return null; + } + } + }); + } + + @NotNull + private static List getAvailableForksFromGit(@NotNull GitRepository gitRepository) { + List forks = new ArrayList(); + 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 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; + } + + @NotNull + public static GithubAuthData runAndGetValidAuthIfNeeded(@Nullable Project project, + @Nullable GithubAuthData auth, + @NotNull ProgressIndicator indicator, + @NotNull ThrowableConsumer task) throws IOException { + if (auth == null) { + return GithubUtil.runAndGetValidAuth(project, indicator, task); + } + else { + task.consume(auth); + return auth; + } + } + + private static class GithubInfo { + @NotNull private final List myBranches; + @NotNull private final GithubAuthData myAuthData; + @Nullable private final String myTargetRemote; + + private GithubInfo(@NotNull GithubAuthData authData, @NotNull List repo, @Nullable String targetRemote) { + myAuthData = authData; + myBranches = repo; + myTargetRemote = targetRemote; + } + + @NotNull + public List getBranches() { + return myBranches; + } + + @NotNull + public GithubAuthData getAuthData() { + return myAuthData; + } + + @Nullable + public String getTargetRemote() { + return myTargetRemote; + } + } + + private static class GithubInfo2 { + @NotNull private final Set myForks; + @NotNull private final GithubAuthData myAuthData; + @NotNull private final GithubRepo mySource; + + private GithubInfo2(@NotNull Set forks, @NotNull GithubAuthData authData, @NotNull GithubRepo source) { + myForks = forks; + myAuthData = authData; + mySource = source; + } + + @NotNull + public Set getForks() { + return myForks; + } + + @NotNull + public GithubAuthData getAuthData() { + return myAuthData; + } + + @NotNull + public GithubRepo getSource() { + return mySource; + } + } + + 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; + } + } +} diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index 30673bfa0a48..fd6bcfcc659e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -19,49 +19,89 @@ 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 git4idea.DialogManager; 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; /** * @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 GithubCreatePullRequestWorker myWorker; - public GithubCreatePullRequestDialog(@NotNull Project project, - @NotNull String repoName, - @NotNull Collection branches, - @Nullable Consumer showDiff, - @NotNull final Runnable showSelectForkDialog) { - super(project, true); - myProject = project; + @Nullable private final GithubFullPath myInitForkPath; - myGithubCreatePullRequestPanel = new GithubCreatePullRequestPanel(showDiff, new Runnable() { + public GithubCreatePullRequestDialog(@NotNull GithubCreatePullRequestWorker worker, @Nullable GithubFullPath forkPath) { + super(worker.getProject(), true); + myWorker = worker; + myProject = myWorker.getProject(); + myInitForkPath = forkPath; + + myGithubCreatePullRequestPanel = new GithubCreatePullRequestPanel(new ActionListener() { @Override - public void run() { - doCancelAction(); - showSelectForkDialog.run(); + public void actionPerformed(ActionEvent e) { + myWorker.showDiffDialog(myGithubCreatePullRequestPanel.getBranch()); } - }); + }, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showTargetDialog(); + } + } + ); + + setTitle("Create Pull Request"); + init(); + } + + @Override + public void show() { + if (myInitForkPath != null) { + setTarget(myInitForkPath); + } + else { + showTargetDialog(); + } + super.show(); + } + + private void showTargetDialog() { + GithubFullPath forkPath = myWorker.showTargetDialog(); + if (forkPath == null) { + doCancelAction(); + return; + } + setTarget(forkPath); + } + + private void setTarget(@NotNull GithubFullPath forkPath) { + Collection branches = myWorker.setTarget(forkPath); + updateBranches(branches, forkPath); + } + + private void updateBranches(@Nullable Collection branches, @NotNull GithubFullPath forkPath) { + if (branches == null) { + doCancelAction(); + return; + } myGithubCreatePullRequestPanel.setBranches(branches); String configBranch = GithubProjectSettings.getInstance(myProject).getCreatePullRequestDefaultBranch(); if (configBranch != null) myGithubCreatePullRequestPanel.setSelectedBranch(configBranch); - myGithubCreatePullRequestPanel.setForkName(repoName); - - setTitle("Create Pull Request"); - init(); + myGithubCreatePullRequestPanel.setForkName(forkPath.getFullName()); } @Nullable @@ -87,17 +127,17 @@ 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(); } @@ -105,6 +145,7 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { protected void doOKAction() { super.doOKAction(); GithubProjectSettings.getInstance(myProject).setCreatePullRequestDefaultBranch(getTargetBranch()); + myWorker.performAction(getTitle(), getDescription(), getTargetBranch()); } @Nullable diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java index 5eec711ee071..5b4fd8ef9a53 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java @@ -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; @@ -41,7 +39,7 @@ public class GithubCreatePullRequestPanel { private JButton mySelectForkButton; private JLabel myForkLabel; - public GithubCreatePullRequestPanel(@Nullable final Consumer showDiff, @NotNull final Runnable showSelectForkDialog) { + public GithubCreatePullRequestPanel(@Nullable final ActionListener showDiffAction, @NotNull final ActionListener selectForkAction) { myDescriptionTextArea.setBorder(BorderFactory.createEtchedBorder()); myBranchModel = new SortedComboBoxModel(new Comparator() { @Override @@ -51,23 +49,8 @@ public class GithubCreatePullRequestPanel { }); myBranchComboBox.setModel(myBranchModel); - if (showDiff != null) { - myShowDiffButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showDiff.consume(getBranch()); - } - }); - } - else { - myShowDiffButton.setEnabled(false); - } - mySelectForkButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showSelectForkDialog.run(); - } - }); + myShowDiffButton.addActionListener(showDiffAction); + mySelectForkButton.addActionListener(selectForkAction); } @NotNull @@ -85,6 +68,10 @@ 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)) { return; From ef619d8da7a1de99913f3cad6799878689598fee Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 3 Oct 2013 19:00:58 +0400 Subject: [PATCH 03/32] IDEA-114360 Github: remove double borders for TextArea inside ScrollPane --- .../plugins/github/ui/GithubCreatePullRequestPanel.form | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form index b468a0b585ab..ed383cf50a11 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form @@ -56,7 +56,7 @@
- + From 98eef3b6529d8f6dee727fc5d42ca57b8d195862 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 3 Oct 2013 19:01:50 +0400 Subject: [PATCH 04/32] Github: remove inspection warning --- .../plugins/github/GithubCreatePullRequestAction.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java index 82a68ba54ea3..2b5002e81aa9 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java @@ -16,7 +16,7 @@ package org.jetbrains.plugins.github; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; @@ -41,8 +41,8 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { } public void update(AnActionEvent e) { - final Project project = e.getData(PlatformDataKeys.PROJECT); - final VirtualFile file = e.getData(PlatformDataKeys.VIRTUAL_FILE); + final Project project = e.getData(CommonDataKeys.PROJECT); + final VirtualFile file = e.getData(CommonDataKeys.VIRTUAL_FILE); if (project == null || project.isDefault()) { setVisibleEnabled(e, false, false); return; @@ -64,8 +64,8 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { @Override public void actionPerformed(AnActionEvent e) { - final Project project = e.getData(PlatformDataKeys.PROJECT); - final VirtualFile file = e.getData(PlatformDataKeys.VIRTUAL_FILE); + final Project project = e.getData(CommonDataKeys.PROJECT); + final VirtualFile file = e.getData(CommonDataKeys.VIRTUAL_FILE); if (project == null || project.isDisposed() || !GithubUtil.testGitExecutable(project)) { return; From 8915d0bf78eaa6133cd25dfd94da0e215fb733b3 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 5 Oct 2013 12:20:53 +0400 Subject: [PATCH 05/32] Github: remove useless 'final' --- .../github/GithubCreatePullRequestWorker.java | 12 ++++++------ .../github/ui/GithubCreatePullRequestDialog.java | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index 67a88990454f..b081cd5d7f58 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -86,9 +86,9 @@ public class GithubCreatePullRequestWorker { @Nullable public static GithubCreatePullRequestWorker createPullRequestWorker(@NotNull final Project project, @Nullable final VirtualFile file) { - final Git git = ServiceManager.getService(Git.class); + Git git = ServiceManager.getService(Git.class); - final GitRepository gitRepository = GithubUtil.getGitRepository(project, file); + GitRepository gitRepository = GithubUtil.getGitRepository(project, file); if (gitRepository == null) { GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find git repository"); return null; @@ -100,15 +100,15 @@ public class GithubCreatePullRequestWorker { GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find GitHub remote"); return null; } - final String remoteName = remote.getFirst().getName(); - final String remoteUrl = remote.getSecond(); - final GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl); + 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; } - final GitLocalBranch currentBranch = gitRepository.getCurrentBranch(); + GitLocalBranch currentBranch = gitRepository.getCurrentBranch(); if (currentBranch == null) { GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "No current branch"); return null; diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index fd6bcfcc659e..6b2fe9a226ea 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -38,7 +38,7 @@ import java.util.Collection; public class GithubCreatePullRequestDialog extends DialogWrapper { @NotNull private final GithubCreatePullRequestPanel myGithubCreatePullRequestPanel; @NotNull private final Project myProject; - @NotNull GithubCreatePullRequestWorker myWorker; + @NotNull private final GithubCreatePullRequestWorker myWorker; @Nullable private final GithubFullPath myInitForkPath; From 3698a197fa051f8dd1a4b9caea7e7da016f9643f Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 5 Oct 2013 12:46:43 +0400 Subject: [PATCH 06/32] Github: get GithubAuthData on worker init --- .../github/GithubCreatePullRequestWorker.java | 128 ++++++------------ 1 file changed, 44 insertions(+), 84 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index b081cd5d7f58..8e5c51f37e6f 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -13,7 +13,6 @@ 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.ThrowableConsumer; import com.intellij.util.ThrowableConvertor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; @@ -58,8 +57,8 @@ public class GithubCreatePullRequestWorker { @NotNull private final String myRemoteName; @NotNull private final String myRemoteUrl; @NotNull private final String myCurrentBranch; + @NotNull private final GithubAuthData myAuth; - private volatile GithubAuthData myAuth; private volatile GithubFullPath myForkPath; private volatile String myTargetRemote; @@ -69,7 +68,8 @@ public class GithubCreatePullRequestWorker { @NotNull GithubFullPath path, @NotNull String remoteName, @NotNull String remoteUrl, - @NotNull String currentBranch) { + @NotNull String currentBranch, + @NotNull GithubAuthData auth) { myProject = project; myGit = git; myGitRepository = gitRepository; @@ -77,6 +77,7 @@ public class GithubCreatePullRequestWorker { myRemoteName = remoteName; myRemoteUrl = remoteUrl; myCurrentBranch = currentBranch; + myAuth = auth; } @NotNull @@ -114,7 +115,25 @@ public class GithubCreatePullRequestWorker { return null; } - return new GithubCreatePullRequestWorker(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch.getName()); + GithubAuthData auth; + try { + auth = GithubUtil + .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor() { + @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 @@ -142,21 +161,13 @@ public class GithubCreatePullRequestWorker { } // load available branches - final AtomicReference> reposRef = new AtomicReference>(); - final GithubAuthData auth = - runAndGetValidAuthIfNeeded(myProject, myAuth, indicator, new ThrowableConsumer() { - @Override - public void consume(GithubAuthData authData) throws IOException { - reposRef.set(ContainerUtil.map(GithubApiUtil.getRepoBranches(authData, forkPath.getUser(), forkPath.getRepository()), - new Function() { - @Override - public String fun(GithubBranch githubBranch) { - return githubBranch.getName(); - } - })); - } - }); - + List repos = ContainerUtil.map(GithubApiUtil.getRepoBranches(myAuth, forkPath.getUser(), forkPath.getRepository()), + new Function() { + @Override + public String fun(GithubBranch githubBranch) { + return githubBranch.getName(); + } + }); // fetch if (targetRemoteName != null) { @@ -167,11 +178,10 @@ public class GithubCreatePullRequestWorker { } } - return new GithubInfo(auth, reposRef.get(), targetRemoteName); + return new GithubInfo(repos, targetRemoteName); } }); - myAuth = info.getAuthData(); myForkPath = forkPath; myTargetRemote = info.getTargetRemote(); return info.getBranches(); @@ -197,7 +207,6 @@ public class GithubCreatePullRequestWorker { if (info == null) { return null; } - myAuth = info.getAuthData(); Convertor getForkPath = new Convertor() { @Nullable @@ -224,15 +233,6 @@ public class GithubCreatePullRequestWorker { new Task.Backgroundable(myProject, "Creating pull request...") { @Override public void run(@NotNull ProgressIndicator indicator) { - if (myAuth == null) { - try { - myAuth = GithubUtil.getValidAuthData(myProject, indicator); - } - catch (GithubAuthenticationCanceledException e) { - return; - } - } - LOG.info("Pushing current branch"); indicator.setText("Pushing current branch..."); GitCommandResult result = myGit.push(myGitRepository, myRemoteName, myRemoteUrl, myCurrentBranch, true); @@ -332,7 +332,7 @@ public class GithubCreatePullRequestWorker { @Nullable private static GithubInfo2 getAvailableForksInModal(@NotNull final Project project, @NotNull final GitRepository gitRepository, - @Nullable final GithubAuthData auth, + @NotNull final GithubAuthData auth, @NotNull final GithubFullPath path) { return GithubUtil.computeValueInModal(project, "Access to GitHub", new Convertor() { @Nullable @@ -342,32 +342,20 @@ public class GithubCreatePullRequestWorker { final Set forks = new HashSet(); // GitHub - final AtomicReference sourceRef = new AtomicReference(); - GithubAuthData authData = - runAndGetValidAuthIfNeeded(project, auth, indicator, new ThrowableConsumer() { - @Override - public void consume(GithubAuthData authData) throws IOException { - GithubRepoDetailed repo = GithubApiUtil.getDetailedRepoInfo(authData, 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()); - } - if (repo.getSource() != null) { - sourceRef.set(repo.getSource()); - } - else { - sourceRef.set(repo); - } - } - }); + 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)); - return new GithubInfo2(forks, authData, sourceRef.get()); + GithubRepo forkTreeRoot = repo.getSource() == null ? repo : repo.getSource(); + return new GithubInfo2(forks, forkTreeRoot); } catch (GithubAuthenticationCanceledException e) { return null; @@ -432,27 +420,11 @@ public class GithubCreatePullRequestWorker { return null; } - @NotNull - public static GithubAuthData runAndGetValidAuthIfNeeded(@Nullable Project project, - @Nullable GithubAuthData auth, - @NotNull ProgressIndicator indicator, - @NotNull ThrowableConsumer task) throws IOException { - if (auth == null) { - return GithubUtil.runAndGetValidAuth(project, indicator, task); - } - else { - task.consume(auth); - return auth; - } - } - private static class GithubInfo { @NotNull private final List myBranches; - @NotNull private final GithubAuthData myAuthData; @Nullable private final String myTargetRemote; - private GithubInfo(@NotNull GithubAuthData authData, @NotNull List repo, @Nullable String targetRemote) { - myAuthData = authData; + private GithubInfo(@NotNull List repo, @Nullable String targetRemote) { myBranches = repo; myTargetRemote = targetRemote; } @@ -462,11 +434,6 @@ public class GithubCreatePullRequestWorker { return myBranches; } - @NotNull - public GithubAuthData getAuthData() { - return myAuthData; - } - @Nullable public String getTargetRemote() { return myTargetRemote; @@ -475,12 +442,10 @@ public class GithubCreatePullRequestWorker { private static class GithubInfo2 { @NotNull private final Set myForks; - @NotNull private final GithubAuthData myAuthData; @NotNull private final GithubRepo mySource; - private GithubInfo2(@NotNull Set forks, @NotNull GithubAuthData authData, @NotNull GithubRepo source) { + private GithubInfo2(@NotNull Set forks, @NotNull GithubRepo source) { myForks = forks; - myAuthData = authData; mySource = source; } @@ -489,11 +454,6 @@ public class GithubCreatePullRequestWorker { return myForks; } - @NotNull - public GithubAuthData getAuthData() { - return myAuthData; - } - @NotNull public GithubRepo getSource() { return mySource; From 1b6833521a3a834b72be98fc9d6bea91b4ee1139 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 5 Oct 2013 12:48:41 +0400 Subject: [PATCH 07/32] Github: rename variable --- .../plugins/github/GithubCreatePullRequestAction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java index 2b5002e81aa9..00db5680d4b9 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java @@ -76,14 +76,14 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { static void createPullRequest(@NotNull Project project, @Nullable VirtualFile file) { final GithubProjectSettings projectSettings = GithubProjectSettings.getInstance(project); - GithubFullPath forkPath = projectSettings.getCreatePullRequestDefaultRepo(); + GithubFullPath defaultForkPath = projectSettings.getCreatePullRequestDefaultRepo(); GithubCreatePullRequestWorker worker = createPullRequestWorker(project, file); if (worker == null) { return; } - GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(worker, forkPath); + GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(worker, defaultForkPath); DialogManager.show(dialog); } } \ No newline at end of file From 01af98e740e0b3446ade60633013a2b93dc6a04f Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 5 Oct 2013 13:06:03 +0400 Subject: [PATCH 08/32] Github: disable 'ShowDiff' button on fetch fault --- .../github/GithubCreatePullRequestWorker.java | 39 ++++++++++++++----- .../ui/GithubCreatePullRequestDialog.java | 13 +++---- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index 8e5c51f37e6f..b18655b8fb63 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -137,7 +137,7 @@ public class GithubCreatePullRequestWorker { } @Nullable - public Collection setTarget(@NotNull final GithubFullPath forkPath) { + public GithubTargetInfo setTarget(@NotNull final GithubFullPath forkPath) { try { GithubInfo info = GithubUtil.computeValueInModal(myProject, "Access to GitHub", new ThrowableConvertor() { @@ -161,13 +161,13 @@ public class GithubCreatePullRequestWorker { } // load available branches - List repos = ContainerUtil.map(GithubApiUtil.getRepoBranches(myAuth, forkPath.getUser(), forkPath.getRepository()), - new Function() { - @Override - public String fun(GithubBranch githubBranch) { - return githubBranch.getName(); - } - }); + List branches = ContainerUtil.map(GithubApiUtil.getRepoBranches(myAuth, forkPath.getUser(), forkPath.getRepository()), + new Function() { + @Override + public String fun(GithubBranch githubBranch) { + return githubBranch.getName(); + } + }); // fetch if (targetRemoteName != null) { @@ -178,13 +178,13 @@ public class GithubCreatePullRequestWorker { } } - return new GithubInfo(repos, targetRemoteName); + return new GithubInfo(branches, targetRemoteName); } }); myForkPath = forkPath; myTargetRemote = info.getTargetRemote(); - return info.getBranches(); + return new GithubTargetInfo(info.getBranches(), myTargetRemote != null); } catch (GithubAuthenticationCanceledException e) { return null; @@ -460,6 +460,25 @@ public class GithubCreatePullRequestWorker { } } + public static class GithubTargetInfo { + @NotNull private final List myBranches; + private final boolean myCanShowDiff; + + private GithubTargetInfo(@NotNull List branches, boolean canShowDiff) { + myBranches = branches; + myCanShowDiff = canShowDiff; + } + + @NotNull + public List getBranches() { + return myBranches; + } + + public boolean isCanShowDiff() { + return myCanShowDiff; + } + } + private static class DiffInfo { @NotNull private final GitCommitCompareInfo myInfo; @NotNull private final String myFrom; diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index 6b2fe9a226ea..9defe79a7d21 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -19,7 +19,6 @@ 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 git4idea.DialogManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -86,16 +85,16 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { } private void setTarget(@NotNull GithubFullPath forkPath) { - Collection branches = myWorker.setTarget(forkPath); - updateBranches(branches, forkPath); - } - - private void updateBranches(@Nullable Collection branches, @NotNull GithubFullPath forkPath) { - if (branches == null) { + GithubCreatePullRequestWorker.GithubTargetInfo forkInfo = myWorker.setTarget(forkPath); + if (forkInfo == null) { doCancelAction(); return; } + myGithubCreatePullRequestPanel.setDiffEnabled(forkInfo.isCanShowDiff()); + updateBranches(forkInfo.getBranches(), forkPath); + } + private void updateBranches(@NotNull Collection branches, @NotNull GithubFullPath forkPath) { myGithubCreatePullRequestPanel.setBranches(branches); String configBranch = GithubProjectSettings.getInstance(myProject).getCreatePullRequestDefaultBranch(); From 9692be1295d1e097e45c8559154be7988d7a8d71 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 5 Oct 2013 13:14:04 +0400 Subject: [PATCH 09/32] Github: move ProjectSettings usage --- .../github/GithubCreatePullRequestAction.java | 6 +----- .../ui/GithubCreatePullRequestDialog.java | 20 +++++++++---------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java index 00db5680d4b9..d7a342cf96d7 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java @@ -25,7 +25,6 @@ import git4idea.repo.GitRepository; import icons.GithubIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.github.api.*; import org.jetbrains.plugins.github.ui.GithubCreatePullRequestDialog; import org.jetbrains.plugins.github.util.*; @@ -75,15 +74,12 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { } static void createPullRequest(@NotNull Project project, @Nullable VirtualFile file) { - final GithubProjectSettings projectSettings = GithubProjectSettings.getInstance(project); - GithubFullPath defaultForkPath = projectSettings.getCreatePullRequestDefaultRepo(); - GithubCreatePullRequestWorker worker = createPullRequestWorker(project, file); if (worker == null) { return; } - GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(worker, defaultForkPath); + GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(worker); DialogManager.show(dialog); } } \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index 9defe79a7d21..ac74aadd7709 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -15,7 +15,6 @@ */ 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; @@ -36,16 +35,14 @@ import java.util.Collection; */ public class GithubCreatePullRequestDialog extends DialogWrapper { @NotNull private final GithubCreatePullRequestPanel myGithubCreatePullRequestPanel; - @NotNull private final Project myProject; @NotNull private final GithubCreatePullRequestWorker myWorker; + @NotNull private final GithubProjectSettings myProjectSettings; - @Nullable private final GithubFullPath myInitForkPath; - - public GithubCreatePullRequestDialog(@NotNull GithubCreatePullRequestWorker worker, @Nullable GithubFullPath forkPath) { + public GithubCreatePullRequestDialog(@NotNull GithubCreatePullRequestWorker worker) { super(worker.getProject(), true); myWorker = worker; - myProject = myWorker.getProject(); - myInitForkPath = forkPath; + + myProjectSettings = GithubProjectSettings.getInstance(myWorker.getProject()); myGithubCreatePullRequestPanel = new GithubCreatePullRequestPanel(new ActionListener() { @Override @@ -66,8 +63,9 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { @Override public void show() { - if (myInitForkPath != null) { - setTarget(myInitForkPath); + GithubFullPath defaultForkPath = myProjectSettings.getCreatePullRequestDefaultRepo(); + if (defaultForkPath != null) { + setTarget(defaultForkPath); } else { showTargetDialog(); @@ -97,7 +95,7 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { private void updateBranches(@NotNull Collection branches, @NotNull GithubFullPath forkPath) { myGithubCreatePullRequestPanel.setBranches(branches); - String configBranch = GithubProjectSettings.getInstance(myProject).getCreatePullRequestDefaultBranch(); + String configBranch = myProjectSettings.getCreatePullRequestDefaultBranch(); if (configBranch != null) myGithubCreatePullRequestPanel.setSelectedBranch(configBranch); myGithubCreatePullRequestPanel.setForkName(forkPath.getFullName()); @@ -143,7 +141,7 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { @Override protected void doOKAction() { super.doOKAction(); - GithubProjectSettings.getInstance(myProject).setCreatePullRequestDefaultBranch(getTargetBranch()); + myProjectSettings.setCreatePullRequestDefaultBranch(getTargetBranch()); myWorker.performAction(getTitle(), getDescription(), getTargetBranch()); } From b1ccaba0e367c3b9fa61f291994daafa2782594e Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 5 Oct 2013 13:21:48 +0400 Subject: [PATCH 10/32] Github: rename variable --- .../plugins/github/GithubCreatePullRequestWorker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index b18655b8fb63..0264bed8e97c 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -288,7 +288,7 @@ public class GithubCreatePullRequestWorker { private static void showDiffByRef(@NotNull final Project project, @Nullable final String branch, @NotNull final GitRepository gitRepository, - @NotNull final String targetRemote, + @NotNull final String targetRemoteName, @NotNull final String currentBranch) { if (branch == null) { return; @@ -298,7 +298,7 @@ public class GithubCreatePullRequestWorker { @Override @Nullable public DiffInfo convert(ProgressIndicator indicator) { - return getDiffInfo(project, gitRepository, currentBranch, targetRemote + "/" + branch); + return getDiffInfo(project, gitRepository, currentBranch, targetRemoteName + "/" + branch); } }); if (info == null) { From 1ed98b1ad4e5641a66a28a2191f7a076c007411b Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 5 Oct 2013 13:33:58 +0400 Subject: [PATCH 11/32] Github: change default value only after successful loading --- .../plugins/github/ui/GithubCreatePullRequestDialog.java | 1 + .../org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index ac74aadd7709..0d173a929fd6 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -88,6 +88,7 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { doCancelAction(); return; } + myProjectSettings.setCreatePullRequestDefaultRepo(forkPath); myGithubCreatePullRequestPanel.setDiffEnabled(forkInfo.isCanShowDiff()); updateBranches(forkInfo.getBranches(), forkPath); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java index 7e42b52b4af5..7f1ae8ccd0b5 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java @@ -68,7 +68,6 @@ public class GithubSelectForkDialog extends DialogWrapper { } else { myFullPath = path; - GithubProjectSettings.getInstance(myProject).setCreatePullRequestDefaultRepo(path); super.doOKAction(); } } From 7b6d42cc0bdd5e2e561e96eb0dea8b9d78fb34dc Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 5 Oct 2013 13:37:29 +0400 Subject: [PATCH 12/32] Github: use dialog manager --- .../plugins/github/GithubCreatePullRequestWorker.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index 0264bed8e97c..1b7819aa54e7 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -1,11 +1,13 @@ 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; @@ -16,6 +18,7 @@ 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; @@ -222,7 +225,7 @@ public class GithubCreatePullRequestWorker { } }; GithubSelectForkDialog dialog = new GithubSelectForkDialog(myProject, info.getForks(), getForkPath); - dialog.show(); + DialogManager.show(dialog); if (!dialog.isOK()) { return null; } From dae8bd84ddfa908c70ac200f74defecb25efcd19 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 5 Oct 2013 13:49:05 +0400 Subject: [PATCH 13/32] Github: use getRequestTitle() instead of getTitle() - typo --- .../ui/GithubCreatePullRequestDialog.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index 0d173a929fd6..b0510a171227 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -29,6 +29,7 @@ import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; +import java.util.Collections; /** * @author Aleksey Pivovarov @@ -102,6 +103,13 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { myGithubCreatePullRequestPanel.setForkName(forkPath.getFullName()); } + @Override + protected void doOKAction() { + super.doOKAction(); + myProjectSettings.setCreatePullRequestDefaultBranch(getTargetBranch()); + myWorker.performAction(getRequestTitle(), getDescription(), getTargetBranch()); + } + @Nullable @Override protected JComponent createCenterPanel() { @@ -139,13 +147,6 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { return myGithubCreatePullRequestPanel.getBranch(); } - @Override - protected void doOKAction() { - super.doOKAction(); - myProjectSettings.setCreatePullRequestDefaultBranch(getTargetBranch()); - myWorker.performAction(getTitle(), getDescription(), getTargetBranch()); - } - @Nullable @Override protected ValidationInfo doValidate() { @@ -163,6 +164,11 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { @TestOnly public void setBranch(String branch) { - myGithubCreatePullRequestPanel.setSelectedBranch(branch); + myGithubCreatePullRequestPanel.setBranches(Collections.singleton(branch)); + } + + @TestOnly + public void createPullRequest() { + myWorker.performAction(getRequestTitle(), getDescription(), getTargetBranch()); } } From c8d8f70a837a47f884ea0302c4878677bddcff44 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 5 Oct 2013 13:53:36 +0400 Subject: [PATCH 14/32] Github: fix tests --- .../github/ui/GithubCreatePullRequestDialog.java | 10 ++++++++++ .../plugins/github/GithubCreatePullRequestTest.java | 6 ++---- .../github/GithubCreatePullRequestTestBase.java | 8 +++----- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index b0510a171227..9dbbec7fb046 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -171,4 +171,14 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { public void createPullRequest() { myWorker.performAction(getRequestTitle(), getDescription(), getTargetBranch()); } + + @TestOnly + public void initTarget(@NotNull GithubFullPath forkPath) { + GithubCreatePullRequestWorker.GithubTargetInfo forkInfo = myWorker.setTarget(forkPath); + if (forkInfo == null) { + doCancelAction(); + return; + } + myGithubCreatePullRequestPanel.setDiffEnabled(forkInfo.isCanShowDiff()); + } } diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTest.java b/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTest.java index aed545b89cea..354dddb866a0 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTest.java @@ -22,8 +22,7 @@ import com.intellij.notification.NotificationType; */ public class GithubCreatePullRequestTest extends GithubCreatePullRequestTestBase { public void testSimple() throws Exception { - registerDefaultCreatePullRequestDialogHandler("master"); - setDefaultForkUser(myLogin1); + registerDefaultCreatePullRequestDialogHandler("master", myLogin1); GithubCreatePullRequestAction.createPullRequest(myProject, myProjectRoot); @@ -33,8 +32,7 @@ public class GithubCreatePullRequestTest extends GithubCreatePullRequestTestBase } public void testParent() throws Exception { - registerDefaultCreatePullRequestDialogHandler("file2"); - setDefaultForkUser(myLogin2); + registerDefaultCreatePullRequestDialogHandler("file2", myLogin2); addRemote(myLogin2); GithubCreatePullRequestAction.createPullRequest(myProject, myProjectRoot); diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java b/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java index ae52eb517418..beef42db060d 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java @@ -72,21 +72,19 @@ 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() { @Override public int handleDialog(GithubCreatePullRequestDialog dialog) { dialog.setRequestTitle(BRANCH_NAME); dialog.setBranch(branch); + dialog.initTarget(new GithubFullPath(user, PROJECT_NAME)); + dialog.createPullRequest(); return DialogWrapper.OK_EXIT_CODE; } }); } - protected void setDefaultForkUser(@NotNull String user) { - GithubProjectSettings.getInstance(myProject).setCreatePullRequestDefaultRepo(new GithubFullPath(user, PROJECT_NAME)); - } - protected void cloneRepo() { git("clone " + PROJECT_URL + " ."); setGitIdentity(myProjectRoot); From c48b4bf8c497feaf595f419330e6422bfbbba277 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 5 Oct 2013 13:55:17 +0400 Subject: [PATCH 15/32] Github: use prefix for @TestOnly functions --- .../plugins/github/ui/GithubCreatePullRequestDialog.java | 9 ++++----- .../plugins/github/ui/GithubSelectForkDialog.java | 2 +- .../plugins/github/GithubCreatePullRequestTestBase.java | 9 ++++----- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index 9dbbec7fb046..73a706661224 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -153,27 +153,26 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { if (StringUtil.isEmptyOrSpaces(getRequestTitle())) { return new ValidationInfo("Title can't be empty'", myGithubCreatePullRequestPanel.getTitleTextField()); } - return null; } @TestOnly - public void setRequestTitle(String title) { + public void testSetRequestTitle(String title) { myGithubCreatePullRequestPanel.setTitle(title); } @TestOnly - public void setBranch(String branch) { + public void testSetBranch(String branch) { myGithubCreatePullRequestPanel.setBranches(Collections.singleton(branch)); } @TestOnly - public void createPullRequest() { + public void testCreatePullRequest() { myWorker.performAction(getRequestTitle(), getDescription(), getTargetBranch()); } @TestOnly - public void initTarget(@NotNull GithubFullPath forkPath) { + public void testSetTarget(@NotNull GithubFullPath forkPath) { GithubCreatePullRequestWorker.GithubTargetInfo forkInfo = myWorker.setTarget(forkPath); if (forkInfo == null) { doCancelAction(); diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java index 7f1ae8ccd0b5..81d88eb70a23 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java @@ -84,7 +84,7 @@ public class GithubSelectForkDialog extends DialogWrapper { } @TestOnly - public void setUser(@NotNull String user) { + public void testSetUser(@NotNull String user) { myPanel.setSelectedUser(user); } } diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java b/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java index beef42db060d..741ccd6e08f4 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java @@ -28,7 +28,6 @@ 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.GithubProjectSettings; import org.jetbrains.plugins.github.util.GithubUrlUtil; import org.jetbrains.plugins.github.util.GithubUtil; @@ -76,10 +75,10 @@ public abstract class GithubCreatePullRequestTestBase extends GithubTest { myDialogManager.registerDialogHandler(GithubCreatePullRequestDialog.class, new TestDialogHandler() { @Override public int handleDialog(GithubCreatePullRequestDialog dialog) { - dialog.setRequestTitle(BRANCH_NAME); - dialog.setBranch(branch); - dialog.initTarget(new GithubFullPath(user, PROJECT_NAME)); - dialog.createPullRequest(); + dialog.testSetRequestTitle(BRANCH_NAME); + dialog.testSetBranch(branch); + dialog.testSetTarget(new GithubFullPath(user, PROJECT_NAME)); + dialog.testCreatePullRequest(); return DialogWrapper.OK_EXIT_CODE; } }); From 1fb43fbd6f9e184d11263f41bd81e91d427d25fa Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 10 Oct 2013 17:00:33 +0400 Subject: [PATCH 16/32] Github: do not hang on cancel initial showTargetDialog --- .../ui/GithubCreatePullRequestDialog.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index 73a706661224..a394c8a8057a 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -69,29 +69,31 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { setTarget(defaultForkPath); } else { - showTargetDialog(); + if (!showTargetDialog()) { + close(CANCEL_EXIT_CODE); + return; + } } super.show(); } - private void showTargetDialog() { + private boolean showTargetDialog() { GithubFullPath forkPath = myWorker.showTargetDialog(); if (forkPath == null) { - doCancelAction(); - return; + return false; } - setTarget(forkPath); + return setTarget(forkPath); } - private void setTarget(@NotNull GithubFullPath forkPath) { + private boolean setTarget(@NotNull GithubFullPath forkPath) { GithubCreatePullRequestWorker.GithubTargetInfo forkInfo = myWorker.setTarget(forkPath); if (forkInfo == null) { - doCancelAction(); - return; + return false; } myProjectSettings.setCreatePullRequestDefaultRepo(forkPath); myGithubCreatePullRequestPanel.setDiffEnabled(forkInfo.isCanShowDiff()); updateBranches(forkInfo.getBranches(), forkPath); + return true; } private void updateBranches(@NotNull Collection branches, @NotNull GithubFullPath forkPath) { From d1ef492a5644ecc9fc3e1ec89d2deca048f00a99 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 12 Oct 2013 12:32:42 +0400 Subject: [PATCH 17/32] Github: change labels --- .../plugins/github/ui/GithubCreatePullRequestPanel.form | 6 +++--- .../jetbrains/plugins/github/ui/GithubSelectForkDialog.java | 2 +- .../jetbrains/plugins/github/ui/GithubSelectForkPanel.form | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form index ed383cf50a11..a1ffaf6304cb 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form @@ -13,7 +13,7 @@ - + @@ -77,7 +77,7 @@ - + @@ -85,7 +85,7 @@ - + diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java index 81d88eb70a23..a16d0754ec0e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java @@ -56,7 +56,7 @@ public class GithubSelectForkDialog extends DialogWrapper { } })); - setTitle("Select Fork Repository"); + setTitle("Select Base Fork Repository"); init(); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.form index 84299e815dc5..8f23fd224598 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.form @@ -13,7 +13,7 @@ - + From 75e30368e4bb37ceeff79f23e23aaa1e4972af95 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 12 Oct 2013 12:39:52 +0400 Subject: [PATCH 18/32] Github: change error message --- .../org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java index a16d0754ec0e..b2a4ab0ad848 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java @@ -64,7 +64,7 @@ public class GithubSelectForkDialog extends DialogWrapper { 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"); + GithubNotifications.showErrorDialog(myProject, "Can't Find Repository", "Can't find fork for selected user"); } else { myFullPath = path; From 296c29af39a5c11593b6893f836c2489aa860a73 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 12 Oct 2013 13:01:39 +0400 Subject: [PATCH 19/32] Github: remove static import --- .../plugins/github/GithubCreatePullRequestAction.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java index d7a342cf96d7..636415e5fcb6 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java @@ -28,7 +28,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.ui.GithubCreatePullRequestDialog; import org.jetbrains.plugins.github.util.*; -import static org.jetbrains.plugins.github.GithubCreatePullRequestWorker.createPullRequestWorker; import static org.jetbrains.plugins.github.util.GithubUtil.setVisibleEnabled; /** @@ -74,7 +73,7 @@ public class GithubCreatePullRequestAction extends DumbAwareAction { } static void createPullRequest(@NotNull Project project, @Nullable VirtualFile file) { - GithubCreatePullRequestWorker worker = createPullRequestWorker(project, file); + GithubCreatePullRequestWorker worker = GithubCreatePullRequestWorker.createPullRequestWorker(project, file); if (worker == null) { return; } From 99b6333b91da038b510fd709a55db0b43f34c0c1 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 12 Oct 2013 13:02:53 +0400 Subject: [PATCH 20/32] Github: optimise imports --- .../jetbrains/plugins/github/GithubCreatePullRequestWorker.java | 2 -- .../org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java | 1 - 2 files changed, 3 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index 1b7819aa54e7..daf70292611f 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -1,13 +1,11 @@ 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; diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java index b2a4ab0ad848..d8ce684eeb38 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java @@ -25,7 +25,6 @@ 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; From 9f28f38d8647e56618627d6f57c7bc5536f34434 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 12 Oct 2013 13:09:23 +0400 Subject: [PATCH 21/32] Github: fix warning --- .../plugins/github/GithubCreatePullRequestWorker.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index daf70292611f..5ec4c340ae64 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -231,6 +231,8 @@ public class GithubCreatePullRequestWorker { } public void performAction(@NotNull final String title, @NotNull final String description, @NotNull final String targetBranch) { + @NotNull final Project project = myProject; + new Task.Backgroundable(myProject, "Creating pull request...") { @Override public void run(@NotNull ProgressIndicator indicator) { @@ -238,7 +240,7 @@ public class GithubCreatePullRequestWorker { 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:
" + result.getErrorOutputAsHtmlString()); + GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Push failed:
" + result.getErrorOutputAsHtmlString()); return; } @@ -246,13 +248,13 @@ public class GithubCreatePullRequestWorker { LOG.info("Creating pull request"); indicator.setText("Creating pull request..."); - GithubPullRequest request = createPullRequest(myProject, myAuth, myForkPath, title, description, baseBranch, targetBranch); + GithubPullRequest request = createPullRequest(project, myAuth, myForkPath, title, description, baseBranch, targetBranch); if (request == null) { return; } GithubNotifications - .showInfoURL(myProject, "Successfully created pull request", "Pull Request #" + request.getNumber(), request.getHtmlUrl()); + .showInfoURL(project, "Successfully created pull request", "Pull Request #" + request.getNumber(), request.getHtmlUrl()); } }.queue(); } From 22f24dc6a9c0e0e485ce17241ea094875ea29a5e Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 12 Oct 2013 13:10:43 +0400 Subject: [PATCH 22/32] Github: capitalise message title --- .../plugins/github/GithubCreatePullRequestWorker.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index 5ec4c340ae64..2c7333519874 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -153,7 +153,7 @@ public class GithubCreatePullRequestWorker { @Override public void run() { responseRef.set(GithubNotifications - .showYesNoDialog(myProject, "Can't find remote", "Configure remote for '" + forkPath.getUser() + "'?")); + .showYesNoDialog(myProject, "Can't Find Remote", "Configure remote for '" + forkPath.getUser() + "'?")); } }, indicator.getModalityState()); if (responseRef.get() == Messages.YES) { @@ -254,7 +254,7 @@ public class GithubCreatePullRequestWorker { } GithubNotifications - .showInfoURL(project, "Successfully created pull request", "Pull Request #" + request.getNumber(), request.getHtmlUrl()); + .showInfoURL(project, "Successfully created pull request", "Pull request #" + request.getNumber(), request.getHtmlUrl()); } }.queue(); } @@ -305,7 +305,7 @@ public class GithubCreatePullRequestWorker { } }); if (info == null) { - GithubNotifications.showErrorDialog(project, "Can't show diff", "Can't get diff info"); + GithubNotifications.showErrorDialog(project, "Can't Show Diff", "Can't get diff info"); return; } From e22af4f8302fa99d764f8f20e15946d00ad4a885 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 12 Oct 2013 13:12:10 +0400 Subject: [PATCH 23/32] Github: rename confusing variable --- .../plugins/github/GithubCreatePullRequestWorker.java | 10 +++++----- .../jetbrains/plugins/github/api/GithubApiUtil.java | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index 2c7333519874..d1df920ffadf 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -244,11 +244,11 @@ public class GithubCreatePullRequestWorker { return; } - String baseBranch = myPath.getUser() + ":" + myCurrentBranch; + String headBranch = myPath.getUser() + ":" + myCurrentBranch; LOG.info("Creating pull request"); indicator.setText("Creating pull request..."); - GithubPullRequest request = createPullRequest(project, myAuth, myForkPath, title, description, baseBranch, targetBranch); + GithubPullRequest request = createPullRequest(project, myAuth, myForkPath, title, description, headBranch, targetBranch); if (request == null) { return; } @@ -277,10 +277,10 @@ public class GithubCreatePullRequestWorker { @NotNull GithubFullPath targetRepo, @NotNull String title, @NotNull String description, - @NotNull String from, - @NotNull String onto) { + @NotNull String head, + @NotNull String base) { try { - return GithubApiUtil.createPullRequest(auth, targetRepo.getUser(), targetRepo.getRepository(), title, description, from, onto); + return GithubApiUtil.createPullRequest(auth, targetRepo.getUser(), targetRepo.getRepository(), title, description, head, base); } catch (IOException e) { GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e); diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java index fddf6441812a..6128b511aadf 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java @@ -534,9 +534,9 @@ public class GithubApiUtil { @NotNull String repo, @NotNull String title, @NotNull String description, - @NotNull String from, - @NotNull String onto) throws IOException { - String request = gson.toJson(new GithubPullRequestRequest(title, description, from, onto)); + @NotNull String head, + @NotNull String base) throws IOException { + String request = gson.toJson(new GithubPullRequestRequest(title, description, head, base)); return createDataFromRaw(fromJson(postRequest(auth, "/repos/" + user + "/" + repo + "/pulls", request), GithubPullRequestRaw.class), GithubPullRequest.class); } From cfc1c106500fa424ae85cbd903406c418885d06e Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 12 Oct 2013 13:21:25 +0400 Subject: [PATCH 24/32] remove newline at the end of xml file --- .idea/libraries/ForkJoin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/libraries/ForkJoin.xml b/.idea/libraries/ForkJoin.xml index 82a323873a69..e72750506660 100644 --- a/.idea/libraries/ForkJoin.xml +++ b/.idea/libraries/ForkJoin.xml @@ -8,4 +8,4 @@ - + \ No newline at end of file From 49234a94515e44dbf4438953bd37b2bfe1082863 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 12 Oct 2013 13:38:39 +0400 Subject: [PATCH 25/32] Github: @NotNull --- .../plugins/github/GithubCreatePullRequestWorker.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index d1df920ffadf..5f3408018482 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -289,14 +289,10 @@ public class GithubCreatePullRequestWorker { } private static void showDiffByRef(@NotNull final Project project, - @Nullable final String branch, + @NotNull 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() { @Override @Nullable From 45921c98c6ab6738b883a7805c5df5aa6a14e9f0 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 12 Oct 2013 15:58:05 +0400 Subject: [PATCH 26/32] Github: remove deprecated tooltip message --- .../plugins/github/ui/GithubCreatePullRequestPanel.form | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form index a1ffaf6304cb..c297c50d4022 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form @@ -46,7 +46,7 @@ - + From c42f75afd4b1a4d7b258293fd227c51bde3bbd09 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 12 Oct 2013 14:36:31 +0400 Subject: [PATCH 27/32] Github: IDEA-113816 show default title/description on creating Pull Request * cache DiffInfo * preload DiffInfo on selecting branch --- .../github/GithubCreatePullRequestWorker.java | 162 +++++++++++++++--- .../ui/GithubCreatePullRequestDialog.java | 39 ++++- .../ui/GithubCreatePullRequestPanel.form | 34 ++-- .../ui/GithubCreatePullRequestPanel.java | 63 ++++++- 4 files changed, 254 insertions(+), 44 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index 5f3408018482..cc7e2b7ad295 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -12,10 +12,12 @@ 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.ThrowableConvertor; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.Convertor; +import com.intellij.util.concurrency.FutureResult; +import com.intellij.util.containers.*; +import com.intellij.util.containers.HashMap; import git4idea.DialogManager; import git4idea.GitCommit; import git4idea.GitLocalBranch; @@ -42,6 +44,9 @@ import org.jetbrains.plugins.github.util.GithubUtil; import java.io.IOException; import java.util.*; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; /** @@ -60,6 +65,8 @@ public class GithubCreatePullRequestWorker { @NotNull private final String myCurrentBranch; @NotNull private final GithubAuthData myAuth; + @NotNull private final Map> myDiffInfos; + private volatile GithubFullPath myForkPath; private volatile String myTargetRemote; @@ -79,6 +86,8 @@ public class GithubCreatePullRequestWorker { myRemoteUrl = remoteUrl; myCurrentBranch = currentBranch; myAuth = auth; + + myDiffInfos = new HashMap>(); } @NotNull @@ -185,6 +194,7 @@ public class GithubCreatePullRequestWorker { myForkPath = forkPath; myTargetRemote = info.getTargetRemote(); + myDiffInfos.clear(); return new GithubTargetInfo(info.getBranches(), myTargetRemote != null); } catch (GithubAuthenticationCanceledException e) { @@ -198,7 +208,15 @@ public class GithubCreatePullRequestWorker { public void showDiffDialog(@NotNull String branch) { if (myTargetRemote != null) { - showDiffByRef(myProject, branch, myGitRepository, myTargetRemote, myCurrentBranch); + DiffInfo info = getDiffInfoWithModal(branch); + if (info == null) { + GithubNotifications.showErrorDialog(myProject, "Can't Show Diff", "Can't get diff info"); + return; + } + + GitCompareBranchesDialog dialog = + new GitCompareBranchesDialog(myProject, info.getTo(), info.getFrom(), info.getInfo(), myGitRepository); + dialog.show(); } } @@ -288,38 +306,99 @@ public class GithubCreatePullRequestWorker { } } - private static void showDiffByRef(@NotNull final Project project, - @NotNull final String branch, - @NotNull final GitRepository gitRepository, - @NotNull final String targetRemoteName, - @NotNull final String currentBranch) { - DiffInfo info = GithubUtil.computeValueInModal(project, "Collecting diff data...", new Convertor() { + @Nullable + private DiffInfo getDiffInfoWithModal(@NotNull final String branch) { + return GithubUtil.computeValueInModal(myProject, "Collecting diff data...", new Convertor() { @Override @Nullable public DiffInfo convert(ProgressIndicator indicator) { - return getDiffInfo(project, gitRepository, currentBranch, targetRemoteName + "/" + branch); + try { + FutureResult future = myDiffInfos.get(branch); + if (future == null) { + return null; + } + return future.get(); + } + catch (InterruptedException e) { + LOG.error(e); + return null; + } + catch (ExecutionException e) { + LOG.error(e); + return null; + } } }); - if (info == null) { - GithubNotifications.showErrorDialog(project, "Can't Show Diff", "Can't get diff info"); + } + + /* + should be called from EDT + */ + public void initLoadDiffInfo(@NotNull final String branch, @Nullable final Consumer after) { + if (myTargetRemote == null) { return; } - GitCompareBranchesDialog dialog = new GitCompareBranchesDialog(project, info.getTo(), info.getFrom(), info.getInfo(), gitRepository); - dialog.show(); + final FutureResult oldFuture = myDiffInfos.get(branch); + if (oldFuture != null) { + if (after != null) { + try { + DiffInfo info = oldFuture.tryGet(); + if (info != null) { + after.consume(getDefaultDescriptionMessage(branch, info)); + return; + } + } + catch (ExecutionException e) { + LOG.error(e); + return; + } + + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + try { + DiffInfo info = oldFuture.get(); + after.consume(getDefaultDescriptionMessage(branch, info)); + } + catch (InterruptedException e) { + LOG.error(e); + } + catch (ExecutionException e) { + LOG.error(e); + } + } + }); + } + return; + } + + final FutureResult future = new FutureResult(); + myDiffInfos.put(branch, future); + + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + DiffInfo info = loadDiffInfo(myProject, myGitRepository, myCurrentBranch, myTargetRemote + "/" + branch); + future.set(info); + if (after != null) { + after.consume(getDefaultDescriptionMessage(branch, info)); + } + } + }); } @Nullable - private static DiffInfo getDiffInfo(@NotNull final Project project, - @NotNull final GitRepository repository, - @NotNull final String currentBranch, - @NotNull final String targetBranch) { + private static DiffInfo loadDiffInfo(@NotNull final Project project, + @NotNull final GitRepository repository, + @NotNull final String currentBranch, + @NotNull final String targetBranch) { try { List commits = GitHistoryUtils.history(project, repository.getRoot(), targetBranch + ".."); Collection 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>create(new ArrayList(), commits)); + info.put(repository, Pair., List>create(Collections.emptyList(), commits)); return new DiffInfo(info, currentBranch, targetBranch); } catch (VcsException e) { @@ -328,6 +407,20 @@ public class GithubCreatePullRequestWorker { } } + @NotNull + private DiffDescription getDefaultDescriptionMessage(@NotNull String branch, @Nullable DiffInfo info) { + if (info == null) { + return new DiffDescription(branch, null, null); + } + + if (info.getInfo().getBranchToHeadCommits(myGitRepository).size() != 1) { + return new DiffDescription(branch, info.getFrom(), null); + } + + GitCommit commit = info.getInfo().getBranchToHeadCommits(myGitRepository).get(0); + return new DiffDescription(branch, commit.getSubject(), commit.getFullMessage()); + } + @Nullable private static GithubInfo2 getAvailableForksInModal(@NotNull final Project project, @NotNull final GitRepository gitRepository, @@ -485,8 +578,8 @@ public class GithubCreatePullRequestWorker { private DiffInfo(@NotNull GitCommitCompareInfo info, @NotNull String from, @NotNull String to) { myInfo = info; - myFrom = from; - myTo = to; + myFrom = from; // HEAD + myTo = to; // BASE } @NotNull @@ -504,4 +597,31 @@ public class GithubCreatePullRequestWorker { return myTo; } } + + public static class DiffDescription { + @NotNull private final String myBranch; + @Nullable private final String myTitle; + @Nullable private final String myDescription; + + public DiffDescription(@NotNull String branch, @Nullable String title, @Nullable String description) { + myBranch = branch; + myTitle = title; + myDescription = description; + } + + @NotNull + public String getBranch() { + return myBranch; + } + + @Nullable + public String getTitle() { + return myTitle; + } + + @Nullable + public String getDescription() { + return myDescription; + } + } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index a394c8a8057a..86ac0f6044f8 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -18,6 +18,8 @@ package org.jetbrains.plugins.github.ui; 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 com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -28,6 +30,8 @@ import org.jetbrains.plugins.github.util.GithubProjectSettings; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.util.Collection; import java.util.Collections; @@ -45,18 +49,45 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { myProjectSettings = GithubProjectSettings.getInstance(myWorker.getProject()); - myGithubCreatePullRequestPanel = new GithubCreatePullRequestPanel(new ActionListener() { + myGithubCreatePullRequestPanel = new GithubCreatePullRequestPanel(); + + myGithubCreatePullRequestPanel.getShowDiffButton().addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { myWorker.showDiffDialog(myGithubCreatePullRequestPanel.getBranch()); } - }, new ActionListener() { + }); + myGithubCreatePullRequestPanel.getSelectForkButton().addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { showTargetDialog(); } - } - ); + }); + myGithubCreatePullRequestPanel.getBranchComboBox().addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + myGithubCreatePullRequestPanel.setBusy(true); + myWorker.initLoadDiffInfo(getTargetBranch(), new Consumer() { + @Override + public void consume(@NotNull final GithubCreatePullRequestWorker.DiffDescription info) { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + if (getTargetBranch().equals(info.getBranch())) { + myGithubCreatePullRequestPanel.setBusy(false); + if (myGithubCreatePullRequestPanel.isTitleDescriptionEmptyOrNotModified()) { + myGithubCreatePullRequestPanel.setTitle(info.getTitle()); + myGithubCreatePullRequestPanel.setDescription(info.getDescription()); + } + } + } + }); + } + }); + } + } + }); setTitle("Create Pull Request"); init(); diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form index c297c50d4022..e19b8601fa01 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form @@ -1,6 +1,6 @@
- + @@ -34,24 +34,15 @@ - + - - - - - - - - - - + @@ -66,7 +57,7 @@ - + @@ -82,7 +73,7 @@ - + @@ -96,6 +87,21 @@ + + + + + + + + + + + + + + + diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java index 5b4fd8ef9a53..e7517ad8c10d 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java @@ -17,12 +17,15 @@ package org.jetbrains.plugins.github.ui; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.DocumentAdapter; import com.intellij.ui.SortedComboBoxModel; +import com.intellij.util.ui.AsyncProcessIcon; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.awt.event.ActionListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import java.util.Collection; import java.util.Comparator; @@ -38,8 +41,11 @@ public class GithubCreatePullRequestPanel { private JButton myShowDiffButton; private JButton mySelectForkButton; private JLabel myForkLabel; + private AsyncProcessIcon myBusyIcon; - public GithubCreatePullRequestPanel(@Nullable final ActionListener showDiffAction, @NotNull final ActionListener selectForkAction) { + private boolean myTitleDescriptionUserModified = false; + + public GithubCreatePullRequestPanel() { myDescriptionTextArea.setBorder(BorderFactory.createEtchedBorder()); myBranchModel = new SortedComboBoxModel(new Comparator() { @Override @@ -49,8 +55,14 @@ public class GithubCreatePullRequestPanel { }); myBranchComboBox.setModel(myBranchModel); - myShowDiffButton.addActionListener(showDiffAction); - mySelectForkButton.addActionListener(selectForkAction); + DocumentListener userModifiedDocumentListener = new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + myTitleDescriptionUserModified = true; + } + }; + myTitleTextField.getDocument().addDocumentListener(userModifiedDocumentListener); + myDescriptionTextArea.getDocument().addDocumentListener(userModifiedDocumentListener); } @NotNull @@ -97,19 +109,60 @@ public class GithubCreatePullRequestPanel { return myTitleTextField; } + @NotNull public JComponent getBranchEditor() { return myBranchComboBox; } + @NotNull public JComponent getTitleTextField() { return myTitleTextField; } - public void setTitle(String title) { + @NotNull + public JButton getShowDiffButton() { + return myShowDiffButton; + } + + @NotNull + public JButton getSelectForkButton() { + return mySelectForkButton; + } + + @NotNull + public ComboBox getBranchComboBox() { + return myBranchComboBox; + } + + public void setTitle(@Nullable String title) { myTitleTextField.setText(title); + myTitleDescriptionUserModified = false; + } + + public void setDescription(@Nullable String title) { + myDescriptionTextArea.setText(title); + myTitleDescriptionUserModified = false; + } + + public boolean isTitleDescriptionEmptyOrNotModified() { + return !myTitleDescriptionUserModified || + (StringUtil.isEmptyOrSpaces(myTitleTextField.getText()) && StringUtil.isEmptyOrSpaces(myDescriptionTextArea.getText())); } public void setForkName(@NotNull String forkName) { myForkLabel.setText(forkName); } + + public void setBusy(boolean enabled) { + if (enabled) { + myBusyIcon.resume(); + } + else { + myBusyIcon.suspend(); + } + } + + private void createUIComponents() { + myBusyIcon = new AsyncProcessIcon("Loading diff..."); + } } From 003fca8eab29ff5d58ec3061b65448bd81c37665 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 21 Oct 2013 12:32:32 +0400 Subject: [PATCH 28/32] Github: add current branch to dialog title --- .../plugins/github/GithubCreatePullRequestWorker.java | 5 +++++ .../plugins/github/ui/GithubCreatePullRequestDialog.java | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index cc7e2b7ad295..2df370415671 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -95,6 +95,11 @@ public class GithubCreatePullRequestWorker { return myProject; } + @NotNull + public String getCurrentBranch() { + return myCurrentBranch; + } + @Nullable public static GithubCreatePullRequestWorker createPullRequestWorker(@NotNull final Project project, @Nullable final VirtualFile file) { Git git = ServiceManager.getService(Git.class); diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index 86ac0f6044f8..67c878456141 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -89,7 +89,7 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { } }); - setTitle("Create Pull Request"); + setTitle("Create Pull Request - " + myWorker.getCurrentBranch()); init(); } From a17f3fd76293de6aae2dcc3758c21c417e702baf Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 21 Oct 2013 12:48:06 +0400 Subject: [PATCH 29/32] Github: do not spin busy on fetch error --- .../github/GithubCreatePullRequestWorker.java | 14 +++---- .../ui/GithubCreatePullRequestDialog.java | 38 ++++++++++--------- .../ui/GithubCreatePullRequestPanel.java | 1 + 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index 2df370415671..14222f83338c 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -100,6 +100,10 @@ public class GithubCreatePullRequestWorker { return myCurrentBranch; } + public boolean canShowDiff() { + return myTargetRemote != null; + } + @Nullable public static GithubCreatePullRequestWorker createPullRequestWorker(@NotNull final Project project, @Nullable final VirtualFile file) { Git git = ServiceManager.getService(Git.class); @@ -200,7 +204,7 @@ public class GithubCreatePullRequestWorker { myForkPath = forkPath; myTargetRemote = info.getTargetRemote(); myDiffInfos.clear(); - return new GithubTargetInfo(info.getBranches(), myTargetRemote != null); + return new GithubTargetInfo(info.getBranches()); } catch (GithubAuthenticationCanceledException e) { return null; @@ -559,21 +563,15 @@ public class GithubCreatePullRequestWorker { public static class GithubTargetInfo { @NotNull private final List myBranches; - private final boolean myCanShowDiff; - private GithubTargetInfo(@NotNull List branches, boolean canShowDiff) { + private GithubTargetInfo(@NotNull List branches) { myBranches = branches; - myCanShowDiff = canShowDiff; } @NotNull public List getBranches() { return myBranches; } - - public boolean isCanShowDiff() { - return myCanShowDiff; - } } private static class DiffInfo { diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index 67c878456141..245d9695ea7c 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -67,24 +67,26 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { - myGithubCreatePullRequestPanel.setBusy(true); - myWorker.initLoadDiffInfo(getTargetBranch(), new Consumer() { - @Override - public void consume(@NotNull final GithubCreatePullRequestWorker.DiffDescription info) { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - if (getTargetBranch().equals(info.getBranch())) { - myGithubCreatePullRequestPanel.setBusy(false); - if (myGithubCreatePullRequestPanel.isTitleDescriptionEmptyOrNotModified()) { - myGithubCreatePullRequestPanel.setTitle(info.getTitle()); - myGithubCreatePullRequestPanel.setDescription(info.getDescription()); + if (myWorker.canShowDiff()) { + myGithubCreatePullRequestPanel.setBusy(true); + myWorker.initLoadDiffInfo(getTargetBranch(), new Consumer() { + @Override + public void consume(@NotNull final GithubCreatePullRequestWorker.DiffDescription info) { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + if (getTargetBranch().equals(info.getBranch())) { + myGithubCreatePullRequestPanel.setBusy(false); + if (myGithubCreatePullRequestPanel.isTitleDescriptionEmptyOrNotModified()) { + myGithubCreatePullRequestPanel.setTitle(info.getTitle()); + myGithubCreatePullRequestPanel.setDescription(info.getDescription()); + } } } - } - }); - } - }); + }); + } + }); + } } } }); @@ -122,7 +124,7 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { return false; } myProjectSettings.setCreatePullRequestDefaultRepo(forkPath); - myGithubCreatePullRequestPanel.setDiffEnabled(forkInfo.isCanShowDiff()); + myGithubCreatePullRequestPanel.setDiffEnabled(myWorker.canShowDiff()); updateBranches(forkInfo.getBranches(), forkPath); return true; } @@ -211,6 +213,6 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { doCancelAction(); return; } - myGithubCreatePullRequestPanel.setDiffEnabled(forkInfo.isCanShowDiff()); + myGithubCreatePullRequestPanel.setDiffEnabled(myWorker.canShowDiff()); } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java index e7517ad8c10d..41512465eeea 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java @@ -164,5 +164,6 @@ public class GithubCreatePullRequestPanel { private void createUIComponents() { myBusyIcon = new AsyncProcessIcon("Loading diff..."); + myBusyIcon.suspend(); } } From 9d206b36c6a7e410b03a7d0332f4ce37ab0a8fcf Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 21 Oct 2013 15:57:59 +0400 Subject: [PATCH 30/32] Github: clean --- .../plugins/github/GithubCreatePullRequestWorker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index 14222f83338c..fcf293a10ccb 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -216,7 +216,7 @@ public class GithubCreatePullRequestWorker { } public void showDiffDialog(@NotNull String branch) { - if (myTargetRemote != null) { + if (canShowDiff()) { DiffInfo info = getDiffInfoWithModal(branch); if (info == null) { GithubNotifications.showErrorDialog(myProject, "Can't Show Diff", "Can't get diff info"); @@ -344,7 +344,7 @@ public class GithubCreatePullRequestWorker { should be called from EDT */ public void initLoadDiffInfo(@NotNull final String branch, @Nullable final Consumer after) { - if (myTargetRemote == null) { + if (!canShowDiff()) { return; } From 74642d33ae78006bbf42e5b95cb88ad4579612a9 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 21 Oct 2013 17:35:17 +0400 Subject: [PATCH 31/32] Github: use FutureTask instead of FutureResult * do not showErrorDialog from Modal thread --- .../github/GithubCreatePullRequestWorker.java | 174 ++++++++---------- .../ui/GithubCreatePullRequestDialog.java | 8 +- 2 files changed, 80 insertions(+), 102 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index fcf293a10ccb..c9805cf10713 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -46,7 +46,9 @@ import java.io.IOException; import java.util.*; import java.util.HashSet; import java.util.List; +import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; import java.util.concurrent.atomic.AtomicReference; /** @@ -65,7 +67,7 @@ public class GithubCreatePullRequestWorker { @NotNull private final String myCurrentBranch; @NotNull private final GithubAuthData myAuth; - @NotNull private final Map> myDiffInfos; + @NotNull private final Map> myDiffInfos; private volatile GithubFullPath myForkPath; private volatile String myTargetRemote; @@ -87,7 +89,7 @@ public class GithubCreatePullRequestWorker { myCurrentBranch = currentBranch; myAuth = auth; - myDiffInfos = new HashMap>(); + myDiffInfos = new HashMap>(); } @NotNull @@ -203,7 +205,19 @@ public class GithubCreatePullRequestWorker { myForkPath = forkPath; myTargetRemote = info.getTargetRemote(); + myDiffInfos.clear(); + if (canShowDiff()) { + for (final String branch : info.getBranches()) { + myDiffInfos.put(branch, new FutureTask(new Callable() { + @Override + public DiffInfo call() throws Exception { + return loadDiffInfo(myProject, myGitRepository, myCurrentBranch, myTargetRemote + "/" + branch); + } + })); + } + } + return new GithubTargetInfo(info.getBranches()); } catch (GithubAuthenticationCanceledException e) { @@ -315,84 +329,42 @@ public class GithubCreatePullRequestWorker { } } + @Nullable + private DiffInfo getDiffInfo(@NotNull String branch) { + try { + FutureTask future = myDiffInfos.get(branch); + if (future == null) { + return null; + } + future.run(); + return future.get(); + } + catch (InterruptedException e) { + LOG.error(e); + return null; + } + catch (ExecutionException e) { + LOG.error(e); + return null; + } + } + @Nullable private DiffInfo getDiffInfoWithModal(@NotNull final String branch) { return GithubUtil.computeValueInModal(myProject, "Collecting diff data...", new Convertor() { @Override @Nullable public DiffInfo convert(ProgressIndicator indicator) { - try { - FutureResult future = myDiffInfos.get(branch); - if (future == null) { - return null; - } - return future.get(); - } - catch (InterruptedException e) { - LOG.error(e); - return null; - } - catch (ExecutionException e) { - LOG.error(e); - return null; - } + return getDiffInfo(branch); } }); } - /* - should be called from EDT - */ - public void initLoadDiffInfo(@NotNull final String branch, @Nullable final Consumer after) { - if (!canShowDiff()) { - return; - } - - final FutureResult oldFuture = myDiffInfos.get(branch); - if (oldFuture != null) { - if (after != null) { - try { - DiffInfo info = oldFuture.tryGet(); - if (info != null) { - after.consume(getDefaultDescriptionMessage(branch, info)); - return; - } - } - catch (ExecutionException e) { - LOG.error(e); - return; - } - - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - try { - DiffInfo info = oldFuture.get(); - after.consume(getDefaultDescriptionMessage(branch, info)); - } - catch (InterruptedException e) { - LOG.error(e); - } - catch (ExecutionException e) { - LOG.error(e); - } - } - }); - } - return; - } - - final FutureResult future = new FutureResult(); - myDiffInfos.put(branch, future); - + public void getDiffDescriptionInPooledThread(@NotNull final String branch, @NotNull final Consumer after) { ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { - DiffInfo info = loadDiffInfo(myProject, myGitRepository, myCurrentBranch, myTargetRemote + "/" + branch); - future.set(info); - if (after != null) { - after.consume(getDefaultDescriptionMessage(branch, info)); - } + after.consume(getDefaultDescriptionMessage(branch, getDiffInfo(branch), myGitRepository)); } }); } @@ -417,16 +389,18 @@ public class GithubCreatePullRequestWorker { } @NotNull - private DiffDescription getDefaultDescriptionMessage(@NotNull String branch, @Nullable DiffInfo info) { + private static DiffDescription getDefaultDescriptionMessage(@NotNull String branch, + @Nullable DiffInfo info, + @NotNull GitRepository gitRepository) { if (info == null) { return new DiffDescription(branch, null, null); } - if (info.getInfo().getBranchToHeadCommits(myGitRepository).size() != 1) { + if (info.getInfo().getBranchToHeadCommits(gitRepository).size() != 1) { return new DiffDescription(branch, info.getFrom(), null); } - GitCommit commit = info.getInfo().getBranchToHeadCommits(myGitRepository).get(0); + GitCommit commit = info.getInfo().getBranchToHeadCommits(gitRepository).get(0); return new DiffDescription(branch, commit.getSubject(), commit.getFullMessage()); } @@ -435,38 +409,38 @@ public class GithubCreatePullRequestWorker { @NotNull final GitRepository gitRepository, @NotNull final GithubAuthData auth, @NotNull final GithubFullPath path) { - return GithubUtil.computeValueInModal(project, "Access to GitHub", new Convertor() { - @Nullable - @Override - public GithubInfo2 convert(ProgressIndicator indicator) { - try { - final Set forks = new HashSet(); + try { + return GithubUtil + .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor() { + @Override + public GithubInfo2 convert(ProgressIndicator indicator) throws IOException { + final Set forks = new HashSet(); - // GitHub - GithubRepoDetailed repo = GithubApiUtil.getDetailedRepoInfo(auth, path.getUser(), path.getRepository()); - forks.add(path); - if (repo.getParent() != null) { - forks.add(repo.getParent().getFullPath()); + // 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); } - 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; - } - } - }); + }); + } + catch (GithubAuthenticationCanceledException e) { + return null; + } + catch (IOException e) { + GithubNotifications.showErrorDialog(project, CANNOT_CREATE_PULL_REQUEST, e); + return null; + } } @NotNull diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index 245d9695ea7c..b49cd82bb685 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -69,12 +69,16 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { if (e.getStateChange() == ItemEvent.SELECTED) { if (myWorker.canShowDiff()) { myGithubCreatePullRequestPanel.setBusy(true); - myWorker.initLoadDiffInfo(getTargetBranch(), new Consumer() { + myWorker.getDiffDescriptionInPooledThread(getTargetBranch(), new Consumer() { @Override - public void consume(@NotNull final GithubCreatePullRequestWorker.DiffDescription info) { + public void consume(final GithubCreatePullRequestWorker.DiffDescription info) { UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { + if (info == null) { + myGithubCreatePullRequestPanel.setBusy(false); + return; + } if (getTargetBranch().equals(info.getBranch())) { myGithubCreatePullRequestPanel.setBusy(false); if (myGithubCreatePullRequestPanel.isTitleDescriptionEmptyOrNotModified()) { From dc862f807e54f86714f742c488d1add81356337b Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 21 Oct 2013 18:14:19 +0400 Subject: [PATCH 32/32] Github: check DiffInfo before performing request * do not allow to create empty PR * ask if base branch is not fully merged --- .../github/GithubCreatePullRequestWorker.java | 27 ++++++++++++++++--- .../ui/GithubCreatePullRequestDialog.java | 8 +++--- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java index c9805cf10713..6e074fff44a0 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java @@ -15,7 +15,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import com.intellij.util.Function; import com.intellij.util.ThrowableConvertor; -import com.intellij.util.concurrency.FutureResult; import com.intellij.util.containers.*; import com.intellij.util.containers.HashMap; import git4idea.DialogManager; @@ -56,7 +55,7 @@ import java.util.concurrent.atomic.AtomicReference; */ public class GithubCreatePullRequestWorker { private static final Logger LOG = GithubUtil.LOG; - private static final String CANNOT_CREATE_PULL_REQUEST = "Can't create pull request"; + private static final String CANNOT_CREATE_PULL_REQUEST = "Can't Create Pull Request"; @NotNull private final Project myProject; @NotNull private final Git myGit; @@ -271,6 +270,25 @@ public class GithubCreatePullRequestWorker { return dialog.getPath(); } + public boolean checkAction(@NotNull String targetBranch) { + DiffInfo info = getDiffInfoWithModal(targetBranch); + if (info == null) { + return true; + } + if (info.getInfo().getBranchToHeadCommits(myGitRepository).isEmpty()) { + GithubNotifications.showWarningDialog(myProject, CANNOT_CREATE_PULL_REQUEST, + "Can't create empty pull request: the branch" + getCurrentBranch() + " in fully merged to the branch " + targetBranch + "."); + return false; + } + if (info.getInfo().getHeadToBranchCommits(myGitRepository).isEmpty()) { + return GithubNotifications + .showYesNoDialog(myProject, "The branch" + targetBranch + " in not fully merged to the branch " + getCurrentBranch(), + "Do you want to proceed anyway?") == Messages.YES; + } + + return true; + } + public void performAction(@NotNull final String title, @NotNull final String description, @NotNull final String targetBranch) { @NotNull final Project project = myProject; @@ -375,11 +393,12 @@ public class GithubCreatePullRequestWorker { @NotNull final String currentBranch, @NotNull final String targetBranch) { try { - List commits = GitHistoryUtils.history(project, repository.getRoot(), targetBranch + ".."); + List commits1 = GitHistoryUtils.history(project, repository.getRoot(), ".." + targetBranch); + List commits2 = GitHistoryUtils.history(project, repository.getRoot(), targetBranch + ".."); Collection 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>create(Collections.emptyList(), commits)); + info.put(repository, Pair.create(commits1, commits2)); return new DiffInfo(info, currentBranch, targetBranch); } catch (VcsException e) { diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java index b49cd82bb685..338003eb4dc7 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java @@ -144,9 +144,11 @@ public class GithubCreatePullRequestDialog extends DialogWrapper { @Override protected void doOKAction() { - super.doOKAction(); - myProjectSettings.setCreatePullRequestDefaultBranch(getTargetBranch()); - myWorker.performAction(getRequestTitle(), getDescription(), getTargetBranch()); + if (myWorker.checkAction(getTargetBranch())) { + myProjectSettings.setCreatePullRequestDefaultBranch(getTargetBranch()); + myWorker.performAction(getRequestTitle(), getDescription(), getTargetBranch()); + super.doOKAction(); + } } @Nullable