mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[github] Multiple accounts support for create pull request action
Action currently requires single account, so selector dialog will be shown in case IDEA is not able to determine the account automatically
This commit is contained in:
+19
-38
@@ -15,63 +15,44 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.github;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import git4idea.DialogManager;
|
||||
import git4idea.repo.GitRemote;
|
||||
import git4idea.repo.GitRepository;
|
||||
import icons.GithubIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.github.authentication.accounts.GithubAccount;
|
||||
import org.jetbrains.plugins.github.ui.GithubCreatePullRequestDialog;
|
||||
import org.jetbrains.plugins.github.util.GithubUtil;
|
||||
|
||||
/**
|
||||
* @author Aleksey Pivovarov
|
||||
*/
|
||||
public class GithubCreatePullRequestAction extends DumbAwareAction {
|
||||
public class GithubCreatePullRequestAction extends LegacySingleAccountActionGroup {
|
||||
public GithubCreatePullRequestAction() {
|
||||
super("Create Pull Request", "Create pull request from current branch", GithubIcons.Github_icon);
|
||||
}
|
||||
|
||||
public void update(AnActionEvent e) {
|
||||
final Project project = e.getData(CommonDataKeys.PROJECT);
|
||||
final VirtualFile file = e.getData(CommonDataKeys.VIRTUAL_FILE);
|
||||
if (project == null || project.isDefault()) {
|
||||
e.getPresentation().setEnabledAndVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
final GitRepository gitRepository = GithubUtil.getGitRepository(project, file);
|
||||
if (gitRepository == null) {
|
||||
e.getPresentation().setEnabledAndVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GithubUtil.isRepositoryOnGitHub(gitRepository)) {
|
||||
e.getPresentation().setEnabledAndVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
e.getPresentation().setEnabledAndVisible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
final Project project = e.getData(CommonDataKeys.PROJECT);
|
||||
final VirtualFile file = e.getData(CommonDataKeys.VIRTUAL_FILE);
|
||||
|
||||
if (project == null || project.isDisposed() || !GithubUtil.testGitExecutable(project)) {
|
||||
return;
|
||||
}
|
||||
|
||||
createPullRequest(project, file);
|
||||
public void actionPerformed(@NotNull Project project,
|
||||
@Nullable VirtualFile file,
|
||||
@NotNull GitRepository gitRepository,
|
||||
@NotNull GithubAccount account) {
|
||||
createPullRequest(project, gitRepository, account);
|
||||
}
|
||||
|
||||
static void createPullRequest(@NotNull Project project, @Nullable VirtualFile file) {
|
||||
GithubCreatePullRequestWorker worker = GithubCreatePullRequestWorker.create(project, file);
|
||||
@Nullable
|
||||
@Override
|
||||
protected Pair<GitRemote, String> getRemote(@NotNull GithubAccount account, @NotNull GitRepository repository) {
|
||||
return GithubCreatePullRequestWorker.findGithubRemote(account, repository);
|
||||
}
|
||||
|
||||
static void createPullRequest(@NotNull Project project,
|
||||
@NotNull GitRepository gitRepository,
|
||||
@NotNull GithubAccount account) {
|
||||
GithubCreatePullRequestWorker worker = GithubCreatePullRequestWorker.create(project, gitRepository, account);
|
||||
if (worker == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
+86
-68
@@ -18,10 +18,7 @@ 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.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.progress.*;
|
||||
import com.intellij.openapi.progress.util.BackgroundTaskUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
@@ -48,12 +45,14 @@ import git4idea.update.GitFetcher;
|
||||
import git4idea.util.GitCommitCompareInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.github.api.GithubApiTaskExecutor;
|
||||
import org.jetbrains.plugins.github.api.GithubApiUtil;
|
||||
import org.jetbrains.plugins.github.api.GithubFullPath;
|
||||
import org.jetbrains.plugins.github.api.data.GithubBranch;
|
||||
import org.jetbrains.plugins.github.api.data.GithubPullRequest;
|
||||
import org.jetbrains.plugins.github.api.data.GithubRepo;
|
||||
import org.jetbrains.plugins.github.api.data.GithubRepoDetailed;
|
||||
import org.jetbrains.plugins.github.authentication.accounts.GithubAccount;
|
||||
import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException;
|
||||
import org.jetbrains.plugins.github.ui.GithubSelectForkDialog;
|
||||
import org.jetbrains.plugins.github.util.*;
|
||||
@@ -74,13 +73,17 @@ public class GithubCreatePullRequestWorker {
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final Git myGit;
|
||||
@NotNull private final GitRepository myGitRepository;
|
||||
@NotNull private final GithubAuthDataHolder myAuthHolder;
|
||||
@NotNull private final GithubAccount myAccount;
|
||||
@NotNull private final GithubApiTaskExecutor myTaskExecutor;
|
||||
@NotNull private final GithubGitHelper myGitHelper;
|
||||
@NotNull private final ProgressManager myProgressManager;
|
||||
|
||||
@NotNull private final GithubFullPath myPath;
|
||||
@NotNull private final String myRemoteName;
|
||||
@NotNull private final String myRemoteUrl;
|
||||
@NotNull private final String myCurrentBranch;
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@NotNull private GithubFullPath mySource;
|
||||
|
||||
@NotNull private final List<ForkInfo> myForks;
|
||||
@@ -89,7 +92,9 @@ public class GithubCreatePullRequestWorker {
|
||||
private GithubCreatePullRequestWorker(@NotNull Project project,
|
||||
@NotNull Git git,
|
||||
@NotNull GitRepository gitRepository,
|
||||
@NotNull GithubAuthDataHolder authHolder,
|
||||
@NotNull GithubAccount account,
|
||||
@NotNull GithubApiTaskExecutor executor,
|
||||
@NotNull GithubGitHelper helper, @NotNull ProgressManager progressManager,
|
||||
@NotNull GithubFullPath path,
|
||||
@NotNull String remoteName,
|
||||
@NotNull String remoteUrl,
|
||||
@@ -97,7 +102,10 @@ public class GithubCreatePullRequestWorker {
|
||||
myProject = project;
|
||||
myGit = git;
|
||||
myGitRepository = gitRepository;
|
||||
myAuthHolder = authHolder;
|
||||
myAccount = account;
|
||||
myTaskExecutor = executor;
|
||||
myGitHelper = helper;
|
||||
myProgressManager = progressManager;
|
||||
myPath = path;
|
||||
myRemoteName = remoteName;
|
||||
myRemoteUrl = remoteUrl;
|
||||
@@ -117,18 +125,15 @@ public class GithubCreatePullRequestWorker {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static GithubCreatePullRequestWorker create(@NotNull final Project project, @Nullable final VirtualFile file) {
|
||||
return GithubUtil.computeValueInModal(project, "Loading data...", indicator -> {
|
||||
public static GithubCreatePullRequestWorker create(@NotNull final Project project,
|
||||
@NotNull GitRepository gitRepository,
|
||||
@NotNull GithubAccount account) {
|
||||
ProgressManager progressManager = ProgressManager.getInstance();
|
||||
return progressManager.runProcessWithProgressSynchronously(() -> {
|
||||
Git git = ServiceManager.getService(Git.class);
|
||||
|
||||
GitRepository gitRepository = GithubUtil.getGitRepository(project, file);
|
||||
if (gitRepository == null) {
|
||||
GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find git repository");
|
||||
return null;
|
||||
}
|
||||
gitRepository.update();
|
||||
|
||||
Pair<GitRemote, String> remote = GithubUtil.findGithubRemote(gitRepository);
|
||||
Pair<GitRemote, String> remote = findGithubRemote(account, gitRepository);
|
||||
if (remote == null) {
|
||||
GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find GitHub remote");
|
||||
return null;
|
||||
@@ -148,20 +153,13 @@ public class GithubCreatePullRequestWorker {
|
||||
return null;
|
||||
}
|
||||
|
||||
GithubAuthDataHolder authHolder;
|
||||
try {
|
||||
authHolder = GithubUtil.getValidAuthDataHolderFromConfig(project, AuthLevel.LOGGED, indicator);
|
||||
}
|
||||
catch (IOException e) {
|
||||
GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
GithubCreatePullRequestWorker worker =
|
||||
new GithubCreatePullRequestWorker(project, git, gitRepository, authHolder, path, remoteName, remoteUrl, currentBranch.getName());
|
||||
new GithubCreatePullRequestWorker(project, git, gitRepository, account, GithubApiTaskExecutor.getInstance(),
|
||||
GithubGitHelper.getInstance(), progressManager, path, remoteName, remoteUrl,
|
||||
currentBranch.getName());
|
||||
|
||||
try {
|
||||
worker.initForks(indicator);
|
||||
worker.initForks(progressManager.getProgressIndicator());
|
||||
}
|
||||
catch (IOException e) {
|
||||
GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
|
||||
@@ -169,7 +167,27 @@ public class GithubCreatePullRequestWorker {
|
||||
}
|
||||
|
||||
return worker;
|
||||
});
|
||||
}, "Loading Data...", true, project);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Pair<GitRemote, String> findGithubRemote(@NotNull GithubAccount account, @NotNull GitRepository repository) {
|
||||
Pair<GitRemote, String> githubRemote = null;
|
||||
for (GitRemote gitRemote : repository.getRemotes()) {
|
||||
for (String remoteUrl : gitRemote.getUrls()) {
|
||||
if (account.getServer().matches(remoteUrl)) {
|
||||
String remoteName = gitRemote.getName();
|
||||
if ("github" == remoteName || "origin" == remoteName) {
|
||||
return Pair.create(gitRemote, remoteUrl);
|
||||
}
|
||||
if (githubRemote == null) {
|
||||
githubRemote = Pair.create(gitRemote, remoteUrl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return githubRemote;
|
||||
}
|
||||
|
||||
private void initForks(@NotNull ProgressIndicator indicator) throws IOException {
|
||||
@@ -178,16 +196,15 @@ public class GithubCreatePullRequestWorker {
|
||||
doLoadForksFromSettings(indicator);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ForkInfo doAddFork(@NotNull GithubFullPath path,
|
||||
@Nullable String remoteName,
|
||||
@NotNull ProgressIndicator indicator) {
|
||||
private void doAddFork(@NotNull GithubFullPath path,
|
||||
@Nullable String remoteName,
|
||||
@NotNull ProgressIndicator indicator) {
|
||||
for (ForkInfo fork : myForks) {
|
||||
if (fork.getPath().equals(path)) {
|
||||
if (fork.getRemoteName() == null && remoteName != null) {
|
||||
fork.setRemoteName(remoteName);
|
||||
}
|
||||
return fork;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,11 +217,9 @@ public class GithubCreatePullRequestWorker {
|
||||
if (remoteName != null) {
|
||||
fork.setRemoteName(remoteName);
|
||||
}
|
||||
return fork;
|
||||
}
|
||||
catch (IOException e) {
|
||||
GithubNotifications.showWarning(myProject, "Can't load branches for " + path.getFullName(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +256,7 @@ public class GithubCreatePullRequestWorker {
|
||||
private void doLoadForksFromGit(@NotNull ProgressIndicator indicator) {
|
||||
for (GitRemote remote : myGitRepository.getRemotes()) {
|
||||
for (String url : remote.getUrls()) {
|
||||
if (GithubUrlUtil.isGithubUrl(url)) {
|
||||
if (myAccount.getServer().matches(url)) {
|
||||
GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(url);
|
||||
if (path != null) {
|
||||
doAddFork(path, remote.getName(), indicator);
|
||||
@@ -253,7 +268,7 @@ public class GithubCreatePullRequestWorker {
|
||||
}
|
||||
|
||||
private void doLoadForksFromGithub(@NotNull ProgressIndicator indicator) throws IOException {
|
||||
GithubRepoDetailed repo = GithubUtil.runTask(myProject, myAuthHolder, indicator, connection ->
|
||||
GithubRepoDetailed repo = myTaskExecutor.execute(indicator, myAccount, connection ->
|
||||
GithubApiUtil.getDetailedRepoInfo(connection, myPath.getUser(), myPath.getRepository()));
|
||||
|
||||
doAddFork(repo, indicator);
|
||||
@@ -269,14 +284,14 @@ public class GithubCreatePullRequestWorker {
|
||||
|
||||
@NotNull
|
||||
private List<String> loadBranches(@NotNull final GithubFullPath fork, @NotNull ProgressIndicator indicator) throws IOException {
|
||||
List<GithubBranch> branches = GithubUtil.runTask(myProject, myAuthHolder, indicator, connection ->
|
||||
List<GithubBranch> branches = myTaskExecutor.execute(indicator, myAccount, connection ->
|
||||
GithubApiUtil.getRepoBranches(connection, fork.getUser(), fork.getRepository()));
|
||||
return ContainerUtil.map(branches, GithubBranch::getName);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String doLoadDefaultBranch(@NotNull final GithubFullPath fork, @NotNull ProgressIndicator indicator) throws IOException {
|
||||
GithubRepo repo = GithubUtil.runTask(myProject, myAuthHolder, indicator, connection ->
|
||||
GithubRepo repo = myTaskExecutor.execute(indicator, myAccount, connection ->
|
||||
GithubApiUtil.getDetailedRepoInfo(connection, fork.getUser(), fork.getRepository()));
|
||||
return repo.getDefaultBranch();
|
||||
}
|
||||
@@ -289,9 +304,7 @@ public class GithubCreatePullRequestWorker {
|
||||
if (fork.getFetchTask() != null) return;
|
||||
|
||||
final MasterFutureTask<Void> task = new MasterFutureTask<>(() -> {
|
||||
BackgroundTaskUtil.runUnderDisposeAwareIndicator(myProject, () -> {
|
||||
doFetchRemote(fork);
|
||||
});
|
||||
BackgroundTaskUtil.runUnderDisposeAwareIndicator(myProject, () -> doFetchRemote(fork));
|
||||
return null;
|
||||
});
|
||||
fork.setFetchTask(task);
|
||||
@@ -339,22 +352,19 @@ public class GithubCreatePullRequestWorker {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean doFetchRemote(@NotNull ForkInfo fork) {
|
||||
if (fork.getRemoteName() == null) return false;
|
||||
private void doFetchRemote(@NotNull ForkInfo fork) {
|
||||
if (fork.getRemoteName() == null) return;
|
||||
|
||||
GitFetchResult result =
|
||||
new GitFetcher(myProject, new EmptyProgressIndicator(), false).fetch(myGitRepository.getRoot(), fork.getRemoteName(), null);
|
||||
if (!result.isSuccess()) {
|
||||
GitFetcher.displayFetchResult(myProject, result, null, result.getErrors());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private DiffInfo doLoadDiffInfo(@NotNull final BranchInfo branch) throws VcsException {
|
||||
// TODO: make cancelable and abort old speculative requests (when intellij.vcs.git will allow to do so)
|
||||
String currentBranch = myCurrentBranch;
|
||||
String targetBranch = branch.getForkInfo().getRemoteName() + "/" + branch.getRemoteName();
|
||||
|
||||
List<GitCommit> commits1 = GitHistoryUtils.history(myProject, myGitRepository.getRoot(), ".." + targetBranch);
|
||||
@@ -364,24 +374,28 @@ public class GithubCreatePullRequestWorker {
|
||||
info.put(myGitRepository, diff);
|
||||
info.put(myGitRepository, Couple.of(commits1, commits2));
|
||||
|
||||
return new DiffInfo(info, currentBranch, targetBranch);
|
||||
return new DiffInfo(info, myCurrentBranch, targetBranch);
|
||||
}
|
||||
|
||||
private void doConfigureRemote(@NotNull ForkInfo fork) {
|
||||
if (fork.getRemoteName() != null) return;
|
||||
|
||||
GithubFullPath path = fork.getPath();
|
||||
String url = GithubUrlUtil.getCloneUrl(path);
|
||||
String url = myGitHelper.getRemoteUrl(myAccount.getServer(), path);
|
||||
|
||||
if (GithubUtil.addGithubRemote(myProject, myGitRepository, path.getUser(), url)) {
|
||||
try {
|
||||
myGit.addRemote(myGitRepository, path.getUser(), url).getOutputOrThrow();
|
||||
myGitRepository.update();
|
||||
fork.setRemoteName(path.getUser());
|
||||
}
|
||||
catch (VcsException e) {
|
||||
GithubNotifications.showError(myProject, "Can't add remote", "Failed to add GitHub remote: '" + url + "'. " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void configureRemote(@NotNull final ForkInfo fork) {
|
||||
GithubUtil.computeValueInModal(myProject, "Creating remote..", false, indicator -> {
|
||||
doConfigureRemote(fork);
|
||||
});
|
||||
myProgressManager.runProcessWithProgressSynchronously(() -> doConfigureRemote(fork),
|
||||
"Creating Remote..", false, myProject);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -393,12 +407,11 @@ public class GithubCreatePullRequestWorker {
|
||||
return getSimpleDefaultDescriptionMessage(branch);
|
||||
}
|
||||
|
||||
return GithubUtil.computeValueInModal(myProject, "Collecting last commits...", true, indicator -> {
|
||||
String localBranch = myCurrentBranch;
|
||||
return myProgressManager.runProcessWithProgressSynchronously(() -> {
|
||||
String targetBranch = branch.getForkInfo().getRemoteName() + "/" + branch.getRemoteName();
|
||||
try {
|
||||
List<VcsCommitMetadata> commits =
|
||||
GitHistoryUtils.readLastCommits(myProject, myGitRepository.getRoot(), localBranch, targetBranch);
|
||||
GitHistoryUtils.readLastCommits(myProject, myGitRepository.getRoot(), myCurrentBranch, targetBranch);
|
||||
if (commits == null) return getSimpleDefaultDescriptionMessage(branch);
|
||||
|
||||
VcsCommitMetadata localCommit = commits.get(0);
|
||||
@@ -416,7 +429,7 @@ public class GithubCreatePullRequestWorker {
|
||||
GithubNotifications.showWarning(myProject, "Can't collect additional data", e);
|
||||
return getSimpleDefaultDescriptionMessage(branch);
|
||||
}
|
||||
});
|
||||
}, "Collecting Last Commits...", true, myProject);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -434,8 +447,9 @@ public class GithubCreatePullRequestWorker {
|
||||
|
||||
DiffInfo info;
|
||||
try {
|
||||
info = GithubUtil.computeValueInModalIO(myProject, "Collecting diff data...", indicator ->
|
||||
GithubUtil.runInterruptable(indicator, () -> getDiffInfo(branch)));
|
||||
info = myProgressManager.runProcessWithProgressSynchronously(
|
||||
() -> GithubUtil.runInterruptable(myProgressManager.getProgressIndicator(), () -> getDiffInfo(branch)),
|
||||
"Collecting Diff Data...", false, myProject);
|
||||
}
|
||||
catch (IOException e) {
|
||||
GithubNotifications.showError(myProject, "Can't collect diff data", e);
|
||||
@@ -475,7 +489,8 @@ 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:<br/>" + result.getErrorOutputAsHtmlString());
|
||||
GithubNotifications.showError(GithubCreatePullRequestWorker.this.myProject, CANNOT_CREATE_PULL_REQUEST,
|
||||
"Push failed:<br/>" + result.getErrorOutputAsHtmlString());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -486,7 +501,7 @@ public class GithubCreatePullRequestWorker {
|
||||
return;
|
||||
}
|
||||
|
||||
GithubNotifications.showInfoURL(myProject, "Successfully created pull request",
|
||||
GithubNotifications.showInfoURL(GithubCreatePullRequestWorker.this.myProject, "Successfully created pull request",
|
||||
"Pull request #" + request.getNumber(), request.getHtmlUrl());
|
||||
}
|
||||
}.queue();
|
||||
@@ -503,7 +518,7 @@ public class GithubCreatePullRequestWorker {
|
||||
final String base = branch.getRemoteName();
|
||||
|
||||
try {
|
||||
return GithubUtil.runTask(myProject, myAuthHolder, indicator, connection ->
|
||||
return myTaskExecutor.execute(indicator, myAccount, connection ->
|
||||
GithubApiUtil.createPullRequest(connection, forkPath.getUser(), forkPath.getRepository(), title, description, head, base));
|
||||
}
|
||||
catch (IOException e) {
|
||||
@@ -520,8 +535,9 @@ public class GithubCreatePullRequestWorker {
|
||||
|
||||
DiffInfo info;
|
||||
try {
|
||||
info = GithubUtil.computeValueInModalIO(myProject, "Collecting diff data...", indicator ->
|
||||
GithubUtil.runInterruptable(indicator, () -> getDiffInfo(branch)));
|
||||
info = myProgressManager.runProcessWithProgressSynchronously(
|
||||
() -> GithubUtil.runInterruptable(myProgressManager.getProgressIndicator(), () -> getDiffInfo(branch)),
|
||||
"Collecting Diff Data...", true, myProject);
|
||||
}
|
||||
catch (IOException e) {
|
||||
GithubNotifications.showError(myProject, "Can't collect diff data", e);
|
||||
@@ -541,14 +557,16 @@ public class GithubCreatePullRequestWorker {
|
||||
public ForkInfo showTargetDialog() {
|
||||
if (myAvailableForks == null) {
|
||||
try {
|
||||
myAvailableForks = GithubUtil.computeValueInModal(myProject, myCurrentBranch, indicator -> getAvailableForks(indicator));
|
||||
myAvailableForks = myProgressManager.runProcessWithProgressSynchronously(
|
||||
() -> getAvailableForks(myProgressManager.getProgressIndicator()), myCurrentBranch, false, myProject);
|
||||
}
|
||||
catch (ProcessCanceledException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
Convertor<String, ForkInfo> getForkPath = user ->
|
||||
GithubUtil.computeValueInModal(myProject, "Access to GitHub", indicator -> findRepositoryByUser(indicator, user));
|
||||
myProgressManager.runProcessWithProgressSynchronously(() -> findRepositoryByUser(myProgressManager.getProgressIndicator(), user),
|
||||
"Access to GitHub", false, myProject);
|
||||
|
||||
GithubSelectForkDialog dialog = new GithubSelectForkDialog(myProject, myAvailableForks, getForkPath);
|
||||
DialogManager.show(dialog);
|
||||
@@ -561,7 +579,7 @@ public class GithubCreatePullRequestWorker {
|
||||
@Nullable
|
||||
private List<GithubFullPath> getAvailableForks(@NotNull ProgressIndicator indicator) {
|
||||
try {
|
||||
List<GithubRepo> forks = GithubUtil.runTask(myProject, myAuthHolder, indicator, connection ->
|
||||
List<GithubRepo> forks = myTaskExecutor.execute(indicator, myAccount, connection ->
|
||||
GithubApiUtil.getForks(connection, mySource.getUser(), mySource.getRepository())
|
||||
);
|
||||
List<GithubFullPath> forkPaths = ContainerUtil.map(forks, GithubRepo::getFullPath);
|
||||
@@ -583,7 +601,7 @@ public class GithubCreatePullRequestWorker {
|
||||
}
|
||||
|
||||
try {
|
||||
GithubRepo repo = GithubUtil.runTask(myProject, myAuthHolder, indicator, connection -> {
|
||||
GithubRepo repo = myTaskExecutor.execute(indicator, myAccount, connection -> {
|
||||
try {
|
||||
GithubRepoDetailed target = GithubApiUtil.getDetailedRepoInfo(connection, user, mySource.getRepository());
|
||||
if (target.getSource() != null && StringUtil.equals(target.getSource().getUserName(), mySource.getUser())) {
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.plugins.github
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
import com.intellij.openapi.ui.ValidationInfo
|
||||
import com.intellij.openapi.util.Pair
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.ui.ColoredListCellRenderer
|
||||
import com.intellij.ui.SimpleTextAttributes
|
||||
import com.intellij.ui.components.JBList
|
||||
import com.intellij.ui.components.JBScrollPane
|
||||
import com.intellij.util.ui.JBDimension
|
||||
import com.intellij.util.ui.JBUI
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import git4idea.DialogManager
|
||||
import git4idea.repo.GitRemote
|
||||
import git4idea.repo.GitRepository
|
||||
import org.jetbrains.plugins.github.authentication.GithubAuthenticationManager
|
||||
import org.jetbrains.plugins.github.authentication.accounts.GithubAccount
|
||||
import org.jetbrains.plugins.github.util.GithubGitHelper
|
||||
import javax.swing.Icon
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JList
|
||||
import javax.swing.JTextArea
|
||||
|
||||
abstract class LegacySingleAccountActionGroup(text: String?, description: String?, icon: Icon?) : DumbAwareAction(text, description, icon) {
|
||||
override fun update(e: AnActionEvent?) {
|
||||
if (e == null) return
|
||||
val project = e.getData(CommonDataKeys.PROJECT)
|
||||
val file = e.getData(CommonDataKeys.VIRTUAL_FILE)
|
||||
if (project == null || project.isDefault) {
|
||||
e.presentation.isEnabledAndVisible = false
|
||||
return
|
||||
}
|
||||
|
||||
val gitRepository = GithubGitHelper.findGitRepository(project, file)
|
||||
if (gitRepository == null) {
|
||||
e.presentation.isEnabledAndVisible = false
|
||||
return
|
||||
}
|
||||
|
||||
if (getAccountsForRemotes(project, gitRepository).isEmpty()) {
|
||||
e.presentation.isEnabledAndVisible = false
|
||||
return
|
||||
}
|
||||
|
||||
e.presentation.isEnabledAndVisible = true
|
||||
}
|
||||
|
||||
override fun actionPerformed(e: AnActionEvent?) {
|
||||
if (e == null) return
|
||||
val project = e.getData(CommonDataKeys.PROJECT)
|
||||
val file = e.getData(CommonDataKeys.VIRTUAL_FILE)
|
||||
if (project == null || project.isDefault) return
|
||||
|
||||
val gitRepository = GithubGitHelper.findGitRepository(project, file)
|
||||
if (gitRepository == null) return
|
||||
gitRepository.update()
|
||||
|
||||
val accounts = getAccountsForRemotes(project, gitRepository)
|
||||
if (accounts.isEmpty()) return
|
||||
val account = if (accounts.size == 1) accounts.first()
|
||||
else {
|
||||
val dialog = ChooseAccountDialog(project, accounts)
|
||||
DialogManager.show(dialog)
|
||||
if (!dialog.isOK) return
|
||||
dialog.getAccount()
|
||||
}
|
||||
|
||||
actionPerformed(project, file, gitRepository, account)
|
||||
}
|
||||
|
||||
abstract fun actionPerformed(project: Project, file: VirtualFile?, gitRepository: GitRepository, account: GithubAccount)
|
||||
|
||||
private fun getAccountsForRemotes(project: Project, repository: GitRepository): List<GithubAccount> {
|
||||
val authenticationManager = service<GithubAuthenticationManager>()
|
||||
val defaultAccount = authenticationManager.getDefaultAccount(project)
|
||||
return if (defaultAccount != null && getRemote(defaultAccount, repository) != null)
|
||||
listOf(defaultAccount)
|
||||
else {
|
||||
authenticationManager.getAccounts().filter { getRemote(it, repository) != null }
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun getRemote(account: GithubAccount, repository: GitRepository): Pair<GitRemote, String>?
|
||||
}
|
||||
|
||||
private class ChooseAccountDialog(project: Project, accounts: List<GithubAccount>) : DialogWrapper(project) {
|
||||
private val text = JTextArea().apply {
|
||||
font = UIUtil.getLabelFont()
|
||||
text = "Default account is not configured for this project. Choose Github account:"
|
||||
lineWrap = true
|
||||
wrapStyleWord = true
|
||||
isEditable = false
|
||||
isFocusable = false
|
||||
isOpaque = false
|
||||
border = null
|
||||
margin = JBUI.emptyInsets()
|
||||
}
|
||||
private val list = JBList<GithubAccount>(accounts).apply {
|
||||
cellRenderer = object : ColoredListCellRenderer<GithubAccount>() {
|
||||
override fun customizeCellRenderer(list: JList<out GithubAccount>,
|
||||
value: GithubAccount,
|
||||
index: Int,
|
||||
selected: Boolean,
|
||||
hasFocus: Boolean) {
|
||||
append(value.name)
|
||||
append(" ")
|
||||
append(value.server.toString(), SimpleTextAttributes.GRAYED_ATTRIBUTES)
|
||||
border = JBUI.Borders.empty(0, UIUtil.DEFAULT_HGAP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
title = "Choose Github Account"
|
||||
setOKButtonText("Choose")
|
||||
init()
|
||||
}
|
||||
|
||||
override fun doValidate(): ValidationInfo? {
|
||||
return if (list.selectedValue == null) ValidationInfo("Account is not selected", list) else null
|
||||
}
|
||||
|
||||
fun getAccount(): GithubAccount = list.selectedValue
|
||||
|
||||
override fun createCenterPanel(): JComponent? {
|
||||
return JBUI.Panels.simplePanel(UIUtil.DEFAULT_HGAP, UIUtil.DEFAULT_VGAP)
|
||||
.addToCenter(JBScrollPane(list).apply { preferredSize = JBDimension(150, 80) })
|
||||
.addToTop(text)
|
||||
}
|
||||
}
|
||||
+13
-2
@@ -4,7 +4,6 @@ package org.jetbrains.plugins.github.authentication
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import git4idea.DialogManager
|
||||
import com.intellij.openapi.components.service
|
||||
import org.jetbrains.annotations.CalledInAny
|
||||
import org.jetbrains.annotations.CalledInAwt
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
@@ -12,8 +11,8 @@ import org.jetbrains.plugins.github.api.GithubServerPath
|
||||
import org.jetbrains.plugins.github.authentication.accounts.GithubAccount
|
||||
import org.jetbrains.plugins.github.authentication.accounts.GithubAccountManager
|
||||
import org.jetbrains.plugins.github.authentication.accounts.GithubProjectDefaultAccountHolder
|
||||
import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException
|
||||
import org.jetbrains.plugins.github.authentication.ui.GithubLoginDialog
|
||||
import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException
|
||||
|
||||
/**
|
||||
* Entry point for interactions with Github authentication subsystem
|
||||
@@ -66,6 +65,11 @@ class GithubAuthenticationManager internal constructor(private val accountManage
|
||||
return project.service<GithubProjectDefaultAccountHolder>().account
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun setDefaultAccount(project: Project, account: GithubAccount?) {
|
||||
project.service<GithubProjectDefaultAccountHolder>().account = account
|
||||
}
|
||||
|
||||
fun ensureHasAccounts(project: Project): Boolean {
|
||||
if (!hasAccounts()) {
|
||||
if (requestNewAccount(project) == null) {
|
||||
@@ -75,6 +79,13 @@ class GithubAuthenticationManager internal constructor(private val accountManage
|
||||
return true
|
||||
}
|
||||
|
||||
fun getSingleOrDefaultAccount(project: Project): GithubAccount? {
|
||||
project.service<GithubProjectDefaultAccountHolder>().account?.let { return it }
|
||||
val accounts = accountManager.accounts
|
||||
if (accounts.size == 1) return accounts.first()
|
||||
return null
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(): GithubAuthenticationManager {
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import git4idea.GitUtil
|
||||
import git4idea.repo.GitRepository
|
||||
import org.jetbrains.plugins.github.api.GithubFullPath
|
||||
import org.jetbrains.plugins.github.api.GithubServerPath
|
||||
import org.jetbrains.plugins.github.authentication.GithubAuthenticationManager
|
||||
|
||||
@@ -15,6 +16,10 @@ import org.jetbrains.plugins.github.authentication.GithubAuthenticationManager
|
||||
class GithubGitHelper(private val githubSettings: GithubSettings,
|
||||
private val authenticationManager: GithubAuthenticationManager) {
|
||||
|
||||
fun getRemoteUrl(server: GithubServerPath, repoPath: GithubFullPath): String {
|
||||
return getRemoteUrl(server, repoPath.user, repoPath.repository)
|
||||
}
|
||||
|
||||
fun getRemoteUrl(server: GithubServerPath, user: String, repo: String): String {
|
||||
return if (githubSettings.isCloneGitUsingSsh) {
|
||||
"git@${server.host}:${server.suffix?.substring(1).orEmpty()}/$user/$repo.git"
|
||||
@@ -25,10 +30,15 @@ class GithubGitHelper(private val githubSettings: GithubSettings,
|
||||
}
|
||||
|
||||
fun getAccessibleRemoteUrls(repository: GitRepository): List<String> {
|
||||
return repository.remotes.map { it.urls }.flatten()
|
||||
.filter { url -> authenticationManager.getAccounts().find { it.server.matches(url) } != null }
|
||||
return repository.remotes.map { it.urls }.flatten().filter(::isRemoteUrlAccessible)
|
||||
}
|
||||
|
||||
fun hasAccessibleRemotes(repository: GitRepository): Boolean {
|
||||
return repository.remotes.map { it.urls }.flatten().any(::isRemoteUrlAccessible)
|
||||
}
|
||||
|
||||
private fun isRemoteUrlAccessible(url: String) = authenticationManager.getAccounts().find { it.server.matches(url) } != null
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun findGitRepository(project: Project, file: VirtualFile?): GitRepository? {
|
||||
|
||||
@@ -282,37 +282,6 @@ public class GithubUtil {
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> T computeValueInModal(@NotNull Project project,
|
||||
@NotNull String caption,
|
||||
@NotNull final Convertor<ProgressIndicator, T> task) {
|
||||
return computeValueInModal(project, caption, true, task);
|
||||
}
|
||||
|
||||
public static <T> T computeValueInModal(@NotNull Project project,
|
||||
@NotNull String caption,
|
||||
boolean canBeCancelled,
|
||||
@NotNull final Convertor<ProgressIndicator, T> task) {
|
||||
return ProgressManager.getInstance().run(new Task.WithResult<T, RuntimeException>(project, caption, canBeCancelled) {
|
||||
@Override
|
||||
protected T compute(@NotNull ProgressIndicator indicator) {
|
||||
return task.convert(indicator);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void computeValueInModal(@NotNull Project project,
|
||||
@NotNull String caption,
|
||||
boolean canBeCancelled,
|
||||
@NotNull final Consumer<ProgressIndicator> task) {
|
||||
ProgressManager.getInstance().run(new Task.WithResult<Void, RuntimeException>(project, caption, canBeCancelled) {
|
||||
@Override
|
||||
protected Void compute(@NotNull ProgressIndicator indicator) {
|
||||
task.consume(indicator);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> T runInterruptable(@NotNull final ProgressIndicator indicator,
|
||||
@NotNull ThrowableComputable<T, IOException> task) throws IOException {
|
||||
ScheduledFuture<?> future = null;
|
||||
|
||||
@@ -16,15 +16,16 @@
|
||||
package org.jetbrains.plugins.github;
|
||||
|
||||
import com.intellij.notification.NotificationType;
|
||||
import org.jetbrains.plugins.github.util.GithubGitHelper;
|
||||
|
||||
/**
|
||||
* @author Aleksey Pivovarov
|
||||
*/
|
||||
public class GithubCreatePullRequestTest extends GithubCreatePullRequestTestBase {
|
||||
public void testSimple() {
|
||||
registerDefaultCreatePullRequestDialogHandler("master", myLogin1);
|
||||
|
||||
GithubCreatePullRequestAction.createPullRequest(myProject, projectRoot);
|
||||
registerDefaultCreatePullRequestDialogHandler("master", myUsername);
|
||||
myAuthenticationManager.setDefaultAccount(myProject, myAccount);
|
||||
GithubCreatePullRequestAction.createPullRequest(myProject, myRepository, myAccount);
|
||||
|
||||
checkNotification(NotificationType.INFORMATION, "Successfully created pull request", null);
|
||||
checkRemoteConfigured();
|
||||
@@ -32,10 +33,10 @@ public class GithubCreatePullRequestTest extends GithubCreatePullRequestTestBase
|
||||
}
|
||||
|
||||
public void testParent() {
|
||||
registerDefaultCreatePullRequestDialogHandler("file2", myLogin2);
|
||||
addRemote(myLogin2);
|
||||
|
||||
GithubCreatePullRequestAction.createPullRequest(myProject, projectRoot);
|
||||
registerDefaultCreatePullRequestDialogHandler("file2", myUsername2);
|
||||
git("remote add somename " + GithubGitHelper.getInstance().getRemoteUrl(myAccount2.getServer(), myUsername2, PROJECT_NAME));
|
||||
myAuthenticationManager.setDefaultAccount(myProject, myAccount);
|
||||
GithubCreatePullRequestAction.createPullRequest(myProject, myRepository, myAccount);
|
||||
|
||||
checkNotification(NotificationType.INFORMATION, "Successfully created pull request", null);
|
||||
checkRemoteConfigured();
|
||||
|
||||
+2
-8
@@ -22,14 +22,12 @@ import com.intellij.util.text.DateFormatUtil;
|
||||
import git4idea.actions.GitInit;
|
||||
import git4idea.commands.Git;
|
||||
import git4idea.repo.GitRepository;
|
||||
import git4idea.test.GitExecutor;
|
||||
import git4idea.test.TestDialogHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.github.api.GithubFullPath;
|
||||
import org.jetbrains.plugins.github.test.GithubTest;
|
||||
import org.jetbrains.plugins.github.ui.GithubCreatePullRequestDialog;
|
||||
import org.jetbrains.plugins.github.util.GithubUrlUtil;
|
||||
import org.jetbrains.plugins.github.util.GithubUtil;
|
||||
import org.jetbrains.plugins.github.util.GithubGitHelper;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@@ -64,7 +62,7 @@ public abstract class GithubCreatePullRequestTestBase extends GithubTest {
|
||||
}
|
||||
|
||||
protected void deleteRemoteBranch() {
|
||||
GitRepository repository = GithubUtil.getGitRepository(myProject, projectRoot);
|
||||
GitRepository repository = GithubGitHelper.findGitRepository(myProject, projectRoot);
|
||||
if (repository != null) {
|
||||
Git.getInstance().push(repository, "origin", PROJECT_URL, ":" + BRANCH_NAME, false);
|
||||
}
|
||||
@@ -94,10 +92,6 @@ public abstract class GithubCreatePullRequestTestBase extends GithubTest {
|
||||
GitInit.refreshAndConfigureVcsMappings(myProject, projectRoot, projectRoot.getPath());
|
||||
}
|
||||
|
||||
protected void addRemote(@NotNull String user) {
|
||||
git("remote add somename " + GithubUrlUtil.getCloneUrl(new GithubFullPath(user, PROJECT_NAME)));
|
||||
}
|
||||
|
||||
protected void createBranch() {
|
||||
git("branch " + BRANCH_NAME);
|
||||
git("checkout " + BRANCH_NAME);
|
||||
|
||||
@@ -163,7 +163,7 @@ public abstract class GithubTest extends GitPlatformTest {
|
||||
protected void checkRemoteConfigured() {
|
||||
assertNotNull(myRepository);
|
||||
|
||||
assertTrue("GitHub remote is not configured", !GithubGitHelper.getInstance().getAccessibleRemoteUrls(myRepository).isEmpty());
|
||||
assertTrue("GitHub remote is not configured", GithubGitHelper.getInstance().hasAccessibleRemotes(myRepository));
|
||||
}
|
||||
|
||||
protected void checkLastCommitPushed() {
|
||||
@@ -224,6 +224,7 @@ public abstract class GithubTest extends GitPlatformTest {
|
||||
protected final void tearDown() throws Exception {
|
||||
try {
|
||||
afterTest();
|
||||
myAuthenticationManager.setDefaultAccount(myProject, null);
|
||||
myAuthenticationManager.clearAccounts();
|
||||
}
|
||||
finally {
|
||||
|
||||
Reference in New Issue
Block a user